From 5d37271c1ad0b924c9bbc449aa1c0bd55ec88cb0 Mon Sep 17 00:00:00 2001 From: Dave Enyeart Date: Thu, 8 Feb 2024 03:40:41 -0500 Subject: [PATCH] Bump github.com/IBM/idemix and github.com/consensys/gnark-crypto (release-2.5) (#4672) Bump github.com/IBM/idemix to get updated github.com/consensys/gnark-crypto. Note that github.com/IBM/idemix pulls in github.com/kilic/bls12-381, which requires build tag "generic" to compile on amd64 in plugin mode. Signed-off-by: David Enyeart --- go.mod | 31 +- go.sum | 94 +- integration/pluggable/pluggable_suite_test.go | 4 +- integration/pluggable/pluggable_test.go | 1 + vendor/github.com/IBM/idemix/.gitignore | 1 + vendor/github.com/IBM/idemix/CONTRIBUTING.md | 16 + vendor/github.com/IBM/idemix/Makefile | 19 +- vendor/github.com/IBM/idemix/RELEASING.md | 13 + vendor/github.com/IBM/idemix/bccsp/bccsp.go | 372 +- .../bccsp/{schemes/dlog => }/handlers/cred.go | 64 +- .../{schemes/dlog => }/handlers/issuer.go | 17 +- .../bccsp/{schemes/dlog => }/handlers/nym.go | 9 +- .../{schemes/dlog => }/handlers/nymsigner.go | 7 +- .../{schemes/dlog => }/handlers/revocation.go | 11 +- .../{schemes/dlog => }/handlers/signer.go | 58 +- .../bccsp/{schemes/dlog => }/handlers/user.go | 7 +- vendor/github.com/IBM/idemix/bccsp/impl.go | 5 +- .../IBM/idemix/bccsp/keystore/dummy.go | 2 +- .../IBM/idemix/bccsp/keystore/kvsbased.go | 4 +- .../IBM/idemix/bccsp/schemes/aries/LICENSE | 201 + .../idemix/bccsp/schemes/aries/blind_sign.go | 202 + .../IBM/idemix/bccsp/schemes/aries/cred.go | 109 + .../IBM/idemix/bccsp/schemes/aries/cred.pb.go | 433 ++ .../IBM/idemix/bccsp/schemes/aries/cred.proto | 65 + .../idemix/bccsp/schemes/aries/credrequest.go | 76 + .../IBM/idemix/bccsp/schemes/aries/issuer.go | 134 + .../idemix/bccsp/schemes/aries/nymsigner.go | 102 + .../idemix/bccsp/schemes/aries/revocation.go | 124 + .../IBM/idemix/bccsp/schemes/aries/signer.go | 794 ++++ .../IBM/idemix/bccsp/schemes/aries/user.go | 85 + .../IBM/idemix/bccsp/schemes/aries/util.go | 81 + .../bccsp/schemes/dlog/bridge/credential.go | 17 +- .../bccsp/schemes/dlog/bridge/credrequest.go | 14 +- .../bccsp/schemes/dlog/bridge/issuer.go | 12 +- .../schemes/dlog/bridge/nymsignaturescheme.go | 6 +- .../bccsp/schemes/dlog/bridge/revocation.go | 2 +- .../schemes/dlog/bridge/signaturescheme.go | 121 +- .../idemix/bccsp/schemes/dlog/bridge/user.go | 8 +- .../bccsp/schemes/dlog/crypto/credrequest.go | 4 +- .../bccsp/schemes/dlog/crypto/idemix.pb.go | 188 +- .../bccsp/schemes/dlog/crypto/idemix.proto | 12 + .../bccsp/schemes/dlog/crypto/issuerkey.go | 4 +- .../bccsp/schemes/dlog/crypto/nymeid.go | 59 + .../idemix/bccsp/schemes/dlog/crypto/nymrh.go | 59 + .../bccsp/schemes/dlog/crypto/nymsignature.go | 16 +- .../dlog/crypto/revocation_authority.go | 3 +- .../bccsp/schemes/dlog/crypto/signature.go | 414 +- .../dlog/crypto/translator/amcl/amcl.pb.go | 13 +- .../dlog/crypto/translator/amcl/fp256bn.go | 8 +- .../idemix/bccsp/schemes/dlog/crypto/util.go | 6 +- .../IBM/idemix/bccsp/schemes/weak-bb/LICENSE | 201 + .../{dlog/crypto => weak-bb}/weak-bb.go | 14 +- .../github.com/IBM/idemix/bccsp/types/LICENSE | 201 + .../idemix/bccsp/{schemes => types}/crypto.go | 2 +- .../dlog/handlers => types}/idemix.go | 50 +- .../bccsp/{schemes => types}/idemixerrs.go | 2 +- .../bccsp/{schemes => types}/idemixopts.go | 84 +- vendor/github.com/IBM/idemix/buf.gen.yaml | 7 + .../common/flogging/fabenc/formatter.go | 7 +- .../idemix/common/flogging/loggerlevels.go | 3 +- vendor/github.com/IBM/idemix/idemixmsp.go | 51 +- .../IBM/idemix/idemixmsp/identities.pb.go | 130 + .../IBM/idemix/idemixmsp/identities.proto | 35 + .../IBM/idemix/idemixmsp/msp_config.pb.go | 239 ++ .../IBM/idemix/idemixmsp/msp_config.proto | 56 + vendor/github.com/IBM/idemix/msp.go | 7 +- vendor/github.com/IBM/mathlib/Makefile | 7 +- .../IBM/mathlib/driver/amcl/custom.go | 31 + .../IBM/mathlib/driver/amcl/fp256bn.go | 267 +- .../IBM/mathlib/driver/amcl/fp256bn_miracl.go | 249 +- .../IBM/mathlib/driver/common/big.go | 94 +- .../IBM/mathlib/driver/common/curve.go | 86 + .../IBM/mathlib/driver/gurvy/bls12-377.go | 368 ++ .../IBM/mathlib/driver/gurvy/bls12-381.go | 408 ++ .../IBM/mathlib/driver/gurvy/bn254.go | 300 +- .../IBM/mathlib/driver/gurvy/custom.go | 191 + .../IBM/mathlib/driver/kilic/bls12-381.go | 429 ++ .../IBM/mathlib/driver/kilic/custom.go | 343 ++ .../IBM/mathlib/driver/kilic/custom_amd64.go | 30 + .../mathlib/driver/kilic/custom_generic.go | 171 + vendor/github.com/IBM/mathlib/driver/math.go | 18 +- vendor/github.com/IBM/mathlib/math.go | 237 +- .../component/kmscrypto/LICENSE | 202 + .../primitive/bbs12381g2pub/bbs12381g2pub.go | 338 ++ .../crypto/primitive/bbs12381g2pub/fr.go | 71 + .../crypto/primitive/bbs12381g2pub/keys.go | 196 + .../bbs12381g2pub/proof_of_knowledge.go | 230 ++ .../primitive/bbs12381g2pub/signature.go | 70 + .../bbs12381g2pub/signature_message.go | 27 + .../bbs12381g2pub/signature_proof.go | 276 ++ .../crypto/primitive/bbs12381g2pub/utils.go | 125 + .../bits-and-blooms/bitset/README.md | 72 +- .../bits-and-blooms/bitset/SECURITY.md | 5 + .../bits-and-blooms/bitset/bitset.go | 510 ++- .../bits-and-blooms/bitset/popcnt_19.go | 17 + .../bits-and-blooms/bitset/popcnt_amd64.go | 4 +- .../bits-and-blooms/bitset/popcnt_generic.go | 1 + .../bits-and-blooms/bitset/select.go | 45 + .../bitset/trailing_zeros_18.go | 1 + .../bitset/trailing_zeros_19.go | 1 + vendor/github.com/consensys/bavard/.gitignore | 2 + vendor/github.com/consensys/bavard/LICENSE | 201 + vendor/github.com/consensys/bavard/README.md | 9 + vendor/github.com/consensys/bavard/bavard.go | 345 ++ vendor/github.com/consensys/bavard/helpers.go | 525 +++ .../gnark-crypto/ecc/bls12-377/bls12-377.go | 156 + .../gnark-crypto/ecc/bls12-377/fp/arith.go | 73 + .../ecc/{bn254/doc.go => bls12-377/fp/asm.go} | 13 +- .../ecc/bls12-377/fp/asm_noadx.go | 28 + .../gnark-crypto/ecc/bls12-377/fp/doc.go | 53 + .../gnark-crypto/ecc/bls12-377/fp/element.go | 1848 +++++++++ .../ecc/bls12-377/fp/element_exp.go | 992 +++++ .../ecc/bls12-377/fp/element_mul_amd64.s | 857 ++++ .../ecc/bls12-377/fp/element_ops_amd64.go | 107 + .../ecc/bls12-377/fp/element_ops_amd64.s | 306 ++ .../ecc/bls12-377/fp/element_ops_purego.go | 745 ++++ .../ecc/bls12-377/fp/element_utils.go | 29 + .../gnark-crypto/ecc/bls12-377/fp/vector.go | 255 ++ .../gnark-crypto/ecc/bls12-377/fr/arith.go | 73 + .../fr/mimc/doc.go => bls12-377/fr/asm.go} | 13 +- .../ecc/bls12-377/fr/asm_noadx.go | 28 + .../gnark-crypto/ecc/bls12-377/fr/doc.go | 53 + .../gnark-crypto/ecc/bls12-377/fr/element.go | 1620 ++++++++ .../ecc/bls12-377/fr/element_exp.go | 623 +++ .../fr/element_mul_amd64.s} | 41 +- .../ecc/bls12-377/fr/element_ops_amd64.go | 107 + .../ecc/bls12-377/fr/element_ops_amd64.s | 230 ++ .../ecc/bls12-377/fr/element_ops_purego.go | 443 ++ .../gnark-crypto/ecc/bls12-377/fr/vector.go | 253 ++ .../gnark-crypto/ecc/bls12-377/g1.go | 1120 ++++++ .../gnark-crypto/ecc/bls12-377/g2.go | 1036 +++++ .../gnark-crypto/ecc/bls12-377/hash_to_g1.go | 329 ++ .../gnark-crypto/ecc/bls12-377/hash_to_g2.go | 809 ++++ .../ecc/bls12-377/internal/fptower/asm.go | 28 + .../bls12-377/internal/fptower/asm_noadx.go | 25 + .../ecc/bls12-377/internal/fptower/e12.go | 862 ++++ .../bls12-377/internal/fptower/e12_pairing.go | 113 + .../ecc/bls12-377/internal/fptower/e2.go | 294 ++ .../bls12-377/internal/fptower/e2_amd64.go | 29 + .../ecc/bls12-377/internal/fptower/e2_amd64.s | 320 ++ .../bls12-377/internal/fptower/e2_bls377.go | 117 + .../bls12-377/internal/fptower/e2_fallback.go | 40 + .../ecc/bls12-377/internal/fptower/e6.go | 339 ++ .../bls12-377/internal/fptower/frobenius.go | 227 ++ .../bls12-377/internal/fptower/parameters.go | 33 + .../gnark-crypto/ecc/bls12-377/marshal.go | 1297 ++++++ .../gnark-crypto/ecc/bls12-377/multiexp.go | 813 ++++ .../ecc/bls12-377/multiexp_affine.go | 710 ++++ .../ecc/bls12-377/multiexp_jacobian.go | 195 + .../gnark-crypto/ecc/bls12-377/pairing.go | 343 ++ .../gnark-crypto/ecc/bls12-381/bls12-381.go | 157 + .../gnark-crypto/ecc/bls12-381/fp/arith.go | 73 + .../fr/mimc/fuzz.go => bls12-381/fp/asm.go} | 23 +- .../ecc/bls12-381/fp/asm_noadx.go | 28 + .../gnark-crypto/ecc/bls12-381/fp/doc.go | 53 + .../gnark-crypto/ecc/bls12-381/fp/element.go | 1794 +++++++++ .../ecc/bls12-381/fp/element_exp.go | 1100 +++++ .../ecc/bls12-381/fp/element_mul_amd64.s | 857 ++++ .../ecc/bls12-381/fp/element_ops_amd64.go | 107 + .../ecc/bls12-381/fp/element_ops_amd64.s | 306 ++ .../ecc/bls12-381/fp/element_ops_purego.go | 745 ++++ .../gnark-crypto/ecc/bls12-381/fp/vector.go | 255 ++ .../gnark-crypto/ecc/bls12-381/fr/arith.go | 73 + .../gnark-crypto/ecc/bls12-381/fr/asm.go | 27 + .../ecc/bls12-381/fr/asm_noadx.go | 28 + .../gnark-crypto/ecc/bls12-381/fr/doc.go | 53 + .../gnark-crypto/ecc/bls12-381/fr/element.go | 1620 ++++++++ .../ecc/bls12-381/fr/element_exp.go | 701 ++++ .../fr/element_mul_amd64.s} | 41 +- .../ecc/bls12-381/fr/element_ops_amd64.go | 107 + .../ecc/bls12-381/fr/element_ops_amd64.s | 230 ++ .../ecc/bls12-381/fr/element_ops_purego.go | 443 ++ .../gnark-crypto/ecc/bls12-381/fr/vector.go | 253 ++ .../gnark-crypto/ecc/bls12-381/g1.go | 1120 ++++++ .../gnark-crypto/ecc/bls12-381/g2.go | 1037 +++++ .../gnark-crypto/ecc/bls12-381/hash_to_g1.go | 340 ++ .../gnark-crypto/ecc/bls12-381/hash_to_g2.go | 409 ++ .../ecc/bls12-381/internal/fptower/asm.go | 28 + .../bls12-381/internal/fptower/asm_noadx.go | 25 + .../ecc/bls12-381/internal/fptower/e12.go | 862 ++++ .../bls12-381/internal/fptower/e12_pairing.go | 117 + .../ecc/bls12-381/internal/fptower/e2.go | 295 ++ .../bls12-381/internal/fptower/e2_amd64.go | 56 + .../ecc/bls12-381/internal/fptower/e2_amd64.s | 3191 +++++++++++++++ .../bls12-381/internal/fptower/e2_bls381.go | 105 + .../internal/fptower/e2_bls381_fallback.go | 41 + .../bls12-381/internal/fptower/e2_fallback.go | 40 + .../ecc/bls12-381/internal/fptower/e6.go | 339 ++ .../bls12-381/internal/fptower/frobenius.go | 261 ++ .../bls12-381/internal/fptower/parameters.go | 33 + .../gnark-crypto/ecc/bls12-381/marshal.go | 1297 ++++++ .../gnark-crypto/ecc/bls12-381/multiexp.go | 813 ++++ .../ecc/bls12-381/multiexp_affine.go | 710 ++++ .../ecc/bls12-381/multiexp_jacobian.go | 195 + .../gnark-crypto/ecc/bls12-381/pairing.go | 347 ++ .../consensys/gnark-crypto/ecc/bn254/bn254.go | 105 +- .../gnark-crypto/ecc/bn254/fp/arith.go | 13 + .../gnark-crypto/ecc/bn254/fp/asm.go | 5 +- .../gnark-crypto/ecc/bn254/fp/asm_noadx.go | 5 +- .../gnark-crypto/ecc/bn254/fp/doc.go | 42 +- .../gnark-crypto/ecc/bn254/fp/element.go | 1402 ++++--- .../gnark-crypto/ecc/bn254/fp/element_fuzz.go | 136 - .../ecc/bn254/fp/element_mul_amd64.s | 5 +- .../ecc/bn254/fp/element_ops_amd64.go | 81 +- .../ecc/bn254/fp/element_ops_amd64.s | 114 +- .../ecc/bn254/fp/element_ops_noasm.go | 78 - .../ecc/bn254/fp/element_ops_purego.go | 443 ++ .../gnark-crypto/ecc/bn254/fp/vector.go | 253 ++ .../gnark-crypto/ecc/bn254/fr/arith.go | 13 + .../gnark-crypto/ecc/bn254/fr/asm.go | 5 +- .../gnark-crypto/ecc/bn254/fr/asm_noadx.go | 5 +- .../gnark-crypto/ecc/bn254/fr/doc.go | 42 +- .../gnark-crypto/ecc/bn254/fr/element.go | 1412 ++++--- .../gnark-crypto/ecc/bn254/fr/element_fuzz.go | 136 - .../ecc/bn254/fr/element_mul_amd64.s | 5 +- .../ecc/bn254/fr/element_ops_amd64.go | 81 +- .../ecc/bn254/fr/element_ops_amd64.s | 114 +- .../ecc/bn254/fr/element_ops_noasm.go | 78 - .../ecc/bn254/fr/element_ops_purego.go | 443 ++ .../gnark-crypto/ecc/bn254/fr/mimc/mimc.go | 174 - .../gnark-crypto/ecc/bn254/fr/vector.go | 253 ++ .../consensys/gnark-crypto/ecc/bn254/fuzz.go | 76 - .../consensys/gnark-crypto/ecc/bn254/g1.go | 407 +- .../consensys/gnark-crypto/ecc/bn254/g2.go | 332 +- .../gnark-crypto/ecc/bn254/hash_to_curve.go | 273 -- .../gnark-crypto/ecc/bn254/hash_to_g1.go | 161 + .../gnark-crypto/ecc/bn254/hash_to_g2.go | 205 + .../ecc/bn254/internal/fptower/asm.go | 2 +- .../ecc/bn254/internal/fptower/asm_noadx.go | 2 +- .../ecc/bn254/internal/fptower/e12.go | 619 ++- .../ecc/bn254/internal/fptower/e12_pairing.go | 37 +- .../ecc/bn254/internal/fptower/e2.go | 88 +- .../ecc/bn254/internal/fptower/e2_adx_amd64.s | 732 ---- .../ecc/bn254/internal/fptower/e2_amd64.go | 16 +- .../ecc/bn254/internal/fptower/e2_amd64.s | 2 - .../ecc/bn254/internal/fptower/e2_bn254.go | 32 +- .../ecc/bn254/internal/fptower/e2_fallback.go | 2 +- .../ecc/bn254/internal/fptower/e6.go | 103 +- .../ecc/bn254/internal/fptower/parameters.go | 33 + .../gnark-crypto/ecc/bn254/marshal.go | 515 ++- .../gnark-crypto/ecc/bn254/multiexp.go | 2684 +++---------- .../gnark-crypto/ecc/bn254/multiexp_affine.go | 712 ++++ .../ecc/bn254/multiexp_jacobian.go | 199 + .../gnark-crypto/ecc/bn254/pairing.go | 305 +- .../consensys/gnark-crypto/ecc/ecc.go | 101 +- .../consensys/gnark-crypto/ecc/ecc.md | 3 + .../consensys/gnark-crypto/ecc/utils.go | 113 +- .../consensys/gnark-crypto/field/field.md | 48 - .../field/generator/config/extension.go | 244 ++ .../config/field_config.go} | 257 +- .../internal/addchain/addchain.go | 2 +- .../gnark-crypto/field/hash/hashutils.go | 94 + .../consensys/gnark-crypto/field/pool/pool.go | 28 + .../internal/generator/config/bls12-377.go | 295 +- .../internal/generator/config/bls12-378.go | 74 + .../internal/generator/config/bls12-381.go | 141 +- .../internal/generator/config/bls24-315.go | 47 +- .../internal/generator/config/bls24-317.go | 86 + .../internal/generator/config/bn254.go | 44 + .../internal/generator/config/bw6-633.go | 99 + .../internal/generator/config/bw6-756.go | 177 + .../internal/generator/config/bw6-761.go | 251 ++ .../internal/generator/config/curve.go | 49 +- .../generator/config/hash_to_curve.go | 202 + .../internal/generator/config/secp256k1.go | 28 + .../internal/generator/config/stark-curve.go | 28 + .../gnark-crypto/internal/parallel/execute.go | 12 + .../fabric-amcl/amcl/FP256BN/ARCH.go | 2 + .../fabric-amcl/amcl/FP256BN/ARCH_32.go | 29 + .../fabric-amcl/amcl/FP256BN/BIG.go | 13 +- .../fabric-amcl/amcl/FP256BN/BIG_32.go | 991 +++++ .../fabric-amcl/amcl/FP256BN/BLS.go | 4 +- .../fabric-amcl/amcl/FP256BN/BLS_32.go | 93 + .../fabric-amcl/amcl/FP256BN/CONFIG_BIG.go | 3 +- .../fabric-amcl/amcl/FP256BN/CONFIG_BIG_32.go | 17 + .../fabric-amcl/amcl/FP256BN/CONFIG_FIELD.go | 8 +- .../amcl/FP256BN/CONFIG_FIELD_32.go | 20 + .../fabric-amcl/amcl/FP256BN/DBIG.go | 4 +- .../fabric-amcl/amcl/FP256BN/DBIG_32.go | 289 ++ .../fabric-amcl/amcl/FP256BN/ECDH.go | 3 +- .../fabric-amcl/amcl/FP256BN/ECDH_32.go | 703 ++++ .../fabric-amcl/amcl/FP256BN/ECP.go | 5 +- .../fabric-amcl/amcl/FP256BN/ECP2.go | 4 +- .../fabric-amcl/amcl/FP256BN/ECP2_32.go | 719 ++++ .../fabric-amcl/amcl/FP256BN/ECP_32.go | 1219 ++++++ .../fabric-amcl/amcl/FP256BN/FP.go | 4 +- .../fabric-amcl/amcl/FP256BN/FP12.go | 324 +- .../fabric-amcl/amcl/FP256BN/FP12_32.go | 1076 +++++ .../fabric-amcl/amcl/FP256BN/FP2.go | 4 +- .../fabric-amcl/amcl/FP256BN/FP2_32.go | 366 ++ .../fabric-amcl/amcl/FP256BN/FP4.go | 4 +- .../fabric-amcl/amcl/FP256BN/FP4_32.go | 646 +++ .../fabric-amcl/amcl/FP256BN/FP_32.go | 600 +++ .../fabric-amcl/amcl/FP256BN/MPIN.go | 17 +- .../fabric-amcl/amcl/FP256BN/MPIN_32.go | 834 ++++ .../fabric-amcl/amcl/FP256BN/PAIR.go | 111 +- .../fabric-amcl/amcl/FP256BN/PAIR_32.go | 766 ++++ .../fabric-amcl/amcl/FP256BN/ROM.go | 3 +- .../fabric-amcl/amcl/FP256BN/ROM_32.go | 53 + .../hyperledger/fabric-amcl/core/AES.go | 2 +- .../hyperledger/fabric-amcl/core/DILITHIUM.go | 1290 ++++++ .../fabric-amcl/core/FP256BN/ARCH.go | 2 + .../fabric-amcl/core/FP256BN/ARCH_32.go | 29 + .../fabric-amcl/core/FP256BN/BIG.go | 219 +- .../fabric-amcl/core/FP256BN/BIG_32.go | 1023 +++++ .../fabric-amcl/core/FP256BN/BLS.go | 69 +- .../fabric-amcl/core/FP256BN/BLS_32.go | 156 + .../fabric-amcl/core/FP256BN/CONFIG_BIG.go | 3 +- .../fabric-amcl/core/FP256BN/CONFIG_BIG_32.go | 37 + .../fabric-amcl/core/FP256BN/CONFIG_FIELD.go | 22 +- .../core/FP256BN/CONFIG_FIELD_32.go | 51 + .../fabric-amcl/core/FP256BN/DBIG.go | 96 +- .../fabric-amcl/core/FP256BN/ECDH.go | 96 +- .../fabric-amcl/core/FP256BN/ECDH_32.go | 382 ++ .../fabric-amcl/core/FP256BN/ECP.go | 1079 ++--- .../fabric-amcl/core/FP256BN/ECP2.go | 461 ++- .../fabric-amcl/core/FP256BN/EDDSA.go | 413 ++ .../fabric-amcl/core/FP256BN/EDDSA_32.go | 413 ++ .../fabric-amcl/core/FP256BN/FP.go | 182 +- .../fabric-amcl/core/FP256BN/FP12.go | 54 +- .../fabric-amcl/core/FP256BN/FP2.go | 177 +- .../fabric-amcl/core/FP256BN/FP2_32.go | 505 +++ .../fabric-amcl/core/FP256BN/FP4.go | 82 +- .../fabric-amcl/core/FP256BN/FP4_32.go | 752 ++++ .../fabric-amcl/core/FP256BN/FP_32.go | 762 ++++ .../fabric-amcl/core/FP256BN/HPKE.go | 317 +- .../fabric-amcl/core/FP256BN/HPKE_32.go | 328 ++ .../fabric-amcl/core/FP256BN/MPIN.go | 39 +- .../fabric-amcl/core/FP256BN/MPIN_32.go | 202 + .../fabric-amcl/core/FP256BN/PAIR.go | 325 +- .../fabric-amcl/core/FP256BN/ROM.go | 8 +- .../fabric-amcl/core/FP256BN/ROM_32.go | 55 + .../hyperledger/fabric-amcl/core/GCM.go | 30 +- .../hyperledger/fabric-amcl/core/HASH256.go | 14 +- .../hyperledger/fabric-amcl/core/HASH384.go | 14 +- .../hyperledger/fabric-amcl/core/HASH512.go | 14 +- .../hyperledger/fabric-amcl/core/HMAC.go | 315 +- .../hyperledger/fabric-amcl/core/KYBER.go | 796 ++++ .../hyperledger/fabric-amcl/core/NHS.go | 548 --- .../hyperledger/fabric-amcl/core/RAND.go | 2 +- .../hyperledger/fabric-amcl/core/SHA3.go | 15 +- .../hyperledger/fabric-amcl/core/SHARE.go | 87 +- vendor/github.com/kilic/bls12-381/.gitignore | 2 + vendor/github.com/kilic/bls12-381/LICENSE | 202 + vendor/github.com/kilic/bls12-381/README.md | 30 + .../kilic/bls12-381/arithmetic_decl.go | 116 + .../kilic/bls12-381/arithmetic_fallback.go | 62 + .../kilic/bls12-381/arithmetic_x86.s | 3558 +++++++++++++++++ .../github.com/kilic/bls12-381/bls12_381.go | 316 ++ .../kilic/bls12-381/field_element.go | 337 ++ vendor/github.com/kilic/bls12-381/fp.go | 350 ++ vendor/github.com/kilic/bls12-381/fp12.go | 287 ++ vendor/github.com/kilic/bls12-381/fp2.go | 393 ++ vendor/github.com/kilic/bls12-381/fp6.go | 364 ++ .../github.com/kilic/bls12-381/fp_fallback.go | 454 +++ vendor/github.com/kilic/bls12-381/fr.go | 383 ++ .../github.com/kilic/bls12-381/fr_fallback.go | 386 ++ vendor/github.com/kilic/bls12-381/g1.go | 846 ++++ vendor/github.com/kilic/bls12-381/g2.go | 889 ++++ vendor/github.com/kilic/bls12-381/glv.go | 200 + vendor/github.com/kilic/bls12-381/gt.go | 106 + .../kilic/bls12-381/hash_to_field.go | 70 + vendor/github.com/kilic/bls12-381/isogeny.go | 211 + vendor/github.com/kilic/bls12-381/pairing.go | 348 ++ vendor/github.com/kilic/bls12-381/swu.go | 142 + vendor/github.com/kilic/bls12-381/utils.go | 13 + vendor/github.com/kilic/bls12-381/wnaf.go | 110 + .../rogpeppe/go-internal/fmtsort/mapelem.go | 3 - .../go-internal/fmtsort/mapelem_1.11.go | 24 - .../rogpeppe/go-internal/fmtsort/sort.go | 25 +- vendor/github.com/spf13/cobra/.travis.yml | 28 - vendor/github.com/spf13/cobra/CHANGELOG.md | 51 - vendor/github.com/spf13/cobra/MAINTAINERS | 13 + vendor/github.com/spf13/cobra/Makefile | 11 +- vendor/github.com/spf13/cobra/README.md | 683 +--- vendor/github.com/spf13/cobra/active_help.go | 49 + vendor/github.com/spf13/cobra/active_help.md | 157 + vendor/github.com/spf13/cobra/args.go | 12 + .../spf13/cobra/bash_completions.go | 73 +- .../spf13/cobra/bash_completions.md | 2 + .../spf13/cobra/bash_completionsV2.go | 369 ++ vendor/github.com/spf13/cobra/command.go | 56 +- .../github.com/spf13/cobra/command_notwin.go | 1 + vendor/github.com/spf13/cobra/command_win.go | 1 + .../{custom_completions.go => completions.go} | 443 +- .../spf13/cobra/fish_completions.go | 185 +- vendor/github.com/spf13/cobra/flag_groups.go | 223 ++ .../spf13/cobra/powershell_completions.go | 45 +- .../spf13/cobra/projects_using_cobra.md | 26 +- .../spf13/cobra/shell_completions.md | 99 +- vendor/github.com/spf13/cobra/user_guide.md | 666 +++ .../github.com/spf13/cobra/zsh_completions.go | 89 +- vendor/go.uber.org/atomic/.codecov.yml | 19 - vendor/go.uber.org/atomic/.gitignore | 12 - vendor/go.uber.org/atomic/.travis.yml | 27 - vendor/go.uber.org/atomic/CHANGELOG.md | 76 - vendor/go.uber.org/atomic/LICENSE.txt | 19 - vendor/go.uber.org/atomic/Makefile | 78 - vendor/go.uber.org/atomic/README.md | 63 - vendor/go.uber.org/atomic/bool.go | 81 - vendor/go.uber.org/atomic/doc.go | 23 - vendor/go.uber.org/atomic/duration.go | 82 - vendor/go.uber.org/atomic/duration_ext.go | 40 - vendor/go.uber.org/atomic/float64.go | 76 - vendor/go.uber.org/atomic/float64_ext.go | 47 - vendor/go.uber.org/atomic/gen.go | 26 - vendor/go.uber.org/atomic/int32.go | 102 - vendor/go.uber.org/atomic/int64.go | 102 - vendor/go.uber.org/atomic/nocmp.go | 35 - vendor/go.uber.org/atomic/string.go | 54 - vendor/go.uber.org/atomic/string_ext.go | 43 - vendor/go.uber.org/atomic/uint32.go | 102 - vendor/go.uber.org/atomic/uint64.go | 102 - vendor/go.uber.org/multierr/.travis.yml | 23 - vendor/go.uber.org/multierr/CHANGELOG.md | 35 + vendor/go.uber.org/multierr/LICENSE.txt | 2 +- vendor/go.uber.org/multierr/Makefile | 6 +- vendor/go.uber.org/multierr/README.md | 30 +- vendor/go.uber.org/multierr/error.go | 415 +- .../value.go => multierr/error_post_go120.go} | 33 +- .../multierr/{go113.go => error_pre_go120.go} | 31 +- vendor/go.uber.org/multierr/glide.yaml | 8 - vendor/go.uber.org/zap/.golangci.yml | 77 + vendor/go.uber.org/zap/.readme.tmpl | 12 +- vendor/go.uber.org/zap/CHANGELOG.md | 351 +- vendor/go.uber.org/zap/CONTRIBUTING.md | 21 +- vendor/go.uber.org/zap/Makefile | 87 +- vendor/go.uber.org/zap/README.md | 47 +- vendor/go.uber.org/zap/array.go | 127 + vendor/go.uber.org/zap/buffer/buffer.go | 5 + vendor/go.uber.org/zap/buffer/pool.go | 20 +- vendor/go.uber.org/zap/config.go | 88 +- vendor/go.uber.org/zap/doc.go | 60 +- vendor/go.uber.org/zap/encoder.go | 2 +- vendor/go.uber.org/zap/error.go | 14 +- vendor/go.uber.org/zap/field.go | 194 +- vendor/go.uber.org/zap/global.go | 1 + vendor/go.uber.org/zap/global_prego112.go | 26 - vendor/go.uber.org/zap/http_handler.go | 44 +- vendor/go.uber.org/zap/internal/exit/exit.go | 22 +- .../internal/level_enabler.go} | 30 +- .../error.go => zap/internal/pool/pool.go} | 51 +- .../zap/internal/stacktrace/stack.go | 181 + vendor/go.uber.org/zap/level.go | 29 +- vendor/go.uber.org/zap/logger.go | 164 +- vendor/go.uber.org/zap/options.go | 21 +- vendor/go.uber.org/zap/sink.go | 101 +- vendor/go.uber.org/zap/stacktrace.go | 85 - vendor/go.uber.org/zap/sugar.go | 200 +- vendor/go.uber.org/zap/writer.go | 23 +- .../zap/zapcore/buffered_write_syncer.go | 31 + vendor/go.uber.org/zap/zapcore/clock.go | 4 +- .../zap/zapcore/console_encoder.go | 20 +- vendor/go.uber.org/zap/zapcore/core.go | 15 +- vendor/go.uber.org/zap/zapcore/encoder.go | 30 +- vendor/go.uber.org/zap/zapcore/entry.go | 94 +- vendor/go.uber.org/zap/zapcore/error.go | 28 +- vendor/go.uber.org/zap/zapcore/hook.go | 9 + .../go.uber.org/zap/zapcore/increase_level.go | 9 + .../go.uber.org/zap/zapcore/json_encoder.go | 263 +- .../bool_ext.go => zap/zapcore/lazy_with.go} | 49 +- vendor/go.uber.org/zap/zapcore/level.go | 54 + .../reflected_encoder.go} | 25 +- vendor/go.uber.org/zap/zapcore/sampler.go | 47 +- vendor/go.uber.org/zap/zapcore/tee.go | 17 +- vendor/go.uber.org/zap/zapgrpc/zapgrpc.go | 18 +- .../zap/zaptest/observer/observer.go | 16 +- vendor/golang.org/x/crypto/blake2b/blake2b.go | 291 ++ .../x/crypto/blake2b/blake2bAVX2_amd64.go | 37 + .../x/crypto/blake2b/blake2bAVX2_amd64.s | 744 ++++ .../x/crypto/blake2b/blake2b_amd64.s | 278 ++ .../x/crypto/blake2b/blake2b_generic.go | 182 + .../x/crypto/blake2b/blake2b_ref.go | 11 + vendor/golang.org/x/crypto/blake2b/blake2x.go | 177 + .../golang.org/x/crypto/blake2b/register.go | 30 + vendor/golang.org/x/crypto/hkdf/hkdf.go | 95 + vendor/golang.org/x/sys/unix/mkerrors.sh | 2 +- vendor/golang.org/x/sys/unix/zerrors_linux.go | 36 +- .../x/sys/unix/zerrors_linux_386.go | 3 + .../x/sys/unix/zerrors_linux_amd64.go | 3 + .../x/sys/unix/zerrors_linux_arm.go | 3 + .../x/sys/unix/zerrors_linux_arm64.go | 3 + .../x/sys/unix/zerrors_linux_loong64.go | 3 + .../x/sys/unix/zerrors_linux_mips.go | 3 + .../x/sys/unix/zerrors_linux_mips64.go | 3 + .../x/sys/unix/zerrors_linux_mips64le.go | 3 + .../x/sys/unix/zerrors_linux_mipsle.go | 3 + .../x/sys/unix/zerrors_linux_ppc.go | 3 + .../x/sys/unix/zerrors_linux_ppc64.go | 3 + .../x/sys/unix/zerrors_linux_ppc64le.go | 3 + .../x/sys/unix/zerrors_linux_riscv64.go | 3 + .../x/sys/unix/zerrors_linux_s390x.go | 3 + .../x/sys/unix/zerrors_linux_sparc64.go | 3 + .../x/sys/unix/zsysnum_linux_386.go | 4 + .../x/sys/unix/zsysnum_linux_amd64.go | 3 + .../x/sys/unix/zsysnum_linux_arm.go | 4 + .../x/sys/unix/zsysnum_linux_arm64.go | 4 + .../x/sys/unix/zsysnum_linux_loong64.go | 4 + .../x/sys/unix/zsysnum_linux_mips.go | 4 + .../x/sys/unix/zsysnum_linux_mips64.go | 4 + .../x/sys/unix/zsysnum_linux_mips64le.go | 4 + .../x/sys/unix/zsysnum_linux_mipsle.go | 4 + .../x/sys/unix/zsysnum_linux_ppc.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64.go | 4 + .../x/sys/unix/zsysnum_linux_ppc64le.go | 4 + .../x/sys/unix/zsysnum_linux_riscv64.go | 4 + .../x/sys/unix/zsysnum_linux_s390x.go | 4 + .../x/sys/unix/zsysnum_linux_sparc64.go | 4 + vendor/golang.org/x/sys/unix/ztypes_linux.go | 125 +- .../golang.org/x/sys/windows/env_windows.go | 17 +- .../x/sys/windows/syscall_windows.go | 3 +- vendor/modules.txt | 90 +- vendor/rsc.io/tmplfunc/LICENSE | 27 + vendor/rsc.io/tmplfunc/README.md | 8 + vendor/rsc.io/tmplfunc/func.go | 205 + vendor/rsc.io/tmplfunc/internal/parse/lex.go | 671 ++++ vendor/rsc.io/tmplfunc/internal/parse/node.go | 972 +++++ .../rsc.io/tmplfunc/internal/parse/parse.go | 756 ++++ vendor/rsc.io/tmplfunc/tmpl.go | 213 + 519 files changed, 96018 insertions(+), 13430 deletions(-) create mode 100644 vendor/github.com/IBM/idemix/.gitignore create mode 100644 vendor/github.com/IBM/idemix/CONTRIBUTING.md create mode 100644 vendor/github.com/IBM/idemix/RELEASING.md rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog => }/handlers/cred.go (63%) rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog => }/handlers/issuer.go (91%) rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog => }/handlers/nym.go (97%) rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog => }/handlers/nymsigner.go (92%) rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog => }/handlers/revocation.go (97%) rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog => }/handlers/signer.go (69%) rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog => }/handlers/user.go (95%) create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/LICENSE create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/blind_sign.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.pb.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.proto create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/credrequest.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/issuer.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/nymsigner.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/revocation.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/signer.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/user.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/aries/util.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymeid.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymrh.go create mode 100644 vendor/github.com/IBM/idemix/bccsp/schemes/weak-bb/LICENSE rename vendor/github.com/IBM/idemix/bccsp/schemes/{dlog/crypto => weak-bb}/weak-bb.go (70%) create mode 100644 vendor/github.com/IBM/idemix/bccsp/types/LICENSE rename vendor/github.com/IBM/idemix/bccsp/{schemes => types}/crypto.go (99%) rename vendor/github.com/IBM/idemix/bccsp/{schemes/dlog/handlers => types}/idemix.go (81%) rename vendor/github.com/IBM/idemix/bccsp/{schemes => types}/idemixerrs.go (98%) rename vendor/github.com/IBM/idemix/bccsp/{schemes => types}/idemixopts.go (79%) create mode 100644 vendor/github.com/IBM/idemix/buf.gen.yaml create mode 100644 vendor/github.com/IBM/idemix/idemixmsp/identities.pb.go create mode 100644 vendor/github.com/IBM/idemix/idemixmsp/identities.proto create mode 100644 vendor/github.com/IBM/idemix/idemixmsp/msp_config.pb.go create mode 100644 vendor/github.com/IBM/idemix/idemixmsp/msp_config.proto create mode 100644 vendor/github.com/IBM/mathlib/driver/amcl/custom.go create mode 100644 vendor/github.com/IBM/mathlib/driver/common/curve.go create mode 100644 vendor/github.com/IBM/mathlib/driver/gurvy/bls12-377.go create mode 100644 vendor/github.com/IBM/mathlib/driver/gurvy/bls12-381.go create mode 100644 vendor/github.com/IBM/mathlib/driver/gurvy/custom.go create mode 100644 vendor/github.com/IBM/mathlib/driver/kilic/bls12-381.go create mode 100644 vendor/github.com/IBM/mathlib/driver/kilic/custom.go create mode 100644 vendor/github.com/IBM/mathlib/driver/kilic/custom_amd64.go create mode 100644 vendor/github.com/IBM/mathlib/driver/kilic/custom_generic.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/LICENSE create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/bbs12381g2pub.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/fr.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/keys.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/proof_of_knowledge.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_message.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_proof.go create mode 100644 vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/utils.go create mode 100644 vendor/github.com/bits-and-blooms/bitset/SECURITY.md create mode 100644 vendor/github.com/bits-and-blooms/bitset/select.go create mode 100644 vendor/github.com/consensys/bavard/.gitignore create mode 100644 vendor/github.com/consensys/bavard/LICENSE create mode 100644 vendor/github.com/consensys/bavard/README.md create mode 100644 vendor/github.com/consensys/bavard/bavard.go create mode 100644 vendor/github.com/consensys/bavard/helpers.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/bls12-377.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/arith.go rename vendor/github.com/consensys/gnark-crypto/ecc/{bn254/doc.go => bls12-377/fp/asm.go} (80%) create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm_noadx.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/doc.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_exp.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_purego.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_utils.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/vector.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/arith.go rename vendor/github.com/consensys/gnark-crypto/ecc/{bn254/fr/mimc/doc.go => bls12-377/fr/asm.go} (80%) create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm_noadx.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/doc.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_exp.go rename vendor/github.com/consensys/gnark-crypto/ecc/{bn254/fp/element_mul_adx_amd64.s => bls12-377/fr/element_mul_amd64.s} (92%) create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_purego.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/vector.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g1.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g2.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12_pairing.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_bls377.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_fallback.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/frobenius.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/parameters.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_affine.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_jacobian.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/bls12-381.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/arith.go rename vendor/github.com/consensys/gnark-crypto/ecc/{bn254/fr/mimc/fuzz.go => bls12-381/fp/asm.go} (73%) create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/asm_noadx.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/doc.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_exp.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_mul_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_purego.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/vector.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/arith.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm_noadx.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/doc.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_exp.go rename vendor/github.com/consensys/gnark-crypto/ecc/{bn254/fr/element_mul_adx_amd64.s => bls12-381/fr/element_mul_amd64.s} (92%) create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_purego.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/vector.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g1.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g2.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g1.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g2.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm_noadx.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12_pairing.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381_fallback.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_fallback.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e6.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/frobenius.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/parameters.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/marshal.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_affine.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_jacobian.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/pairing.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_fuzz.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_noasm.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_purego.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/vector.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_fuzz.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_noasm.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_purego.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/mimc.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/vector.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/fuzz.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_curve.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g1.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g2.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_adx_amd64.s create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/parameters.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_affine.go create mode 100644 vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_jacobian.go delete mode 100644 vendor/github.com/consensys/gnark-crypto/field/field.md create mode 100644 vendor/github.com/consensys/gnark-crypto/field/generator/config/extension.go rename vendor/github.com/consensys/gnark-crypto/field/{field.go => generator/config/field_config.go} (55%) rename vendor/github.com/consensys/gnark-crypto/field/{ => generator}/internal/addchain/addchain.go (99%) create mode 100644 vendor/github.com/consensys/gnark-crypto/field/hash/hashutils.go create mode 100644 vendor/github.com/consensys/gnark-crypto/field/pool/pool.go create mode 100644 vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-378.go create mode 100644 vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-317.go create mode 100644 vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-756.go create mode 100644 vendor/github.com/consensys/gnark-crypto/internal/generator/config/hash_to_curve.go create mode 100644 vendor/github.com/consensys/gnark-crypto/internal/generator/config/secp256k1.go create mode 100644 vendor/github.com/consensys/gnark-crypto/internal/generator/config/stark-curve.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/DILITHIUM.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BLS_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/CONFIG_BIG_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/CONFIG_FIELD_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/EDDSA.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/EDDSA_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP2_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP4_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/HPKE_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/MPIN_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ROM_32.go create mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/KYBER.go delete mode 100644 vendor/github.com/hyperledger/fabric-amcl/core/NHS.go create mode 100644 vendor/github.com/kilic/bls12-381/.gitignore create mode 100644 vendor/github.com/kilic/bls12-381/LICENSE create mode 100644 vendor/github.com/kilic/bls12-381/README.md create mode 100644 vendor/github.com/kilic/bls12-381/arithmetic_decl.go create mode 100644 vendor/github.com/kilic/bls12-381/arithmetic_fallback.go create mode 100644 vendor/github.com/kilic/bls12-381/arithmetic_x86.s create mode 100644 vendor/github.com/kilic/bls12-381/bls12_381.go create mode 100644 vendor/github.com/kilic/bls12-381/field_element.go create mode 100644 vendor/github.com/kilic/bls12-381/fp.go create mode 100644 vendor/github.com/kilic/bls12-381/fp12.go create mode 100644 vendor/github.com/kilic/bls12-381/fp2.go create mode 100644 vendor/github.com/kilic/bls12-381/fp6.go create mode 100644 vendor/github.com/kilic/bls12-381/fp_fallback.go create mode 100644 vendor/github.com/kilic/bls12-381/fr.go create mode 100644 vendor/github.com/kilic/bls12-381/fr_fallback.go create mode 100644 vendor/github.com/kilic/bls12-381/g1.go create mode 100644 vendor/github.com/kilic/bls12-381/g2.go create mode 100644 vendor/github.com/kilic/bls12-381/glv.go create mode 100644 vendor/github.com/kilic/bls12-381/gt.go create mode 100644 vendor/github.com/kilic/bls12-381/hash_to_field.go create mode 100644 vendor/github.com/kilic/bls12-381/isogeny.go create mode 100644 vendor/github.com/kilic/bls12-381/pairing.go create mode 100644 vendor/github.com/kilic/bls12-381/swu.go create mode 100644 vendor/github.com/kilic/bls12-381/utils.go create mode 100644 vendor/github.com/kilic/bls12-381/wnaf.go delete mode 100644 vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem_1.11.go delete mode 100644 vendor/github.com/spf13/cobra/.travis.yml delete mode 100644 vendor/github.com/spf13/cobra/CHANGELOG.md create mode 100644 vendor/github.com/spf13/cobra/MAINTAINERS create mode 100644 vendor/github.com/spf13/cobra/active_help.go create mode 100644 vendor/github.com/spf13/cobra/active_help.md create mode 100644 vendor/github.com/spf13/cobra/bash_completionsV2.go rename vendor/github.com/spf13/cobra/{custom_completions.go => completions.go} (58%) create mode 100644 vendor/github.com/spf13/cobra/flag_groups.go create mode 100644 vendor/github.com/spf13/cobra/user_guide.md delete mode 100644 vendor/go.uber.org/atomic/.codecov.yml delete mode 100644 vendor/go.uber.org/atomic/.gitignore delete mode 100644 vendor/go.uber.org/atomic/.travis.yml delete mode 100644 vendor/go.uber.org/atomic/CHANGELOG.md delete mode 100644 vendor/go.uber.org/atomic/LICENSE.txt delete mode 100644 vendor/go.uber.org/atomic/Makefile delete mode 100644 vendor/go.uber.org/atomic/README.md delete mode 100644 vendor/go.uber.org/atomic/bool.go delete mode 100644 vendor/go.uber.org/atomic/doc.go delete mode 100644 vendor/go.uber.org/atomic/duration.go delete mode 100644 vendor/go.uber.org/atomic/duration_ext.go delete mode 100644 vendor/go.uber.org/atomic/float64.go delete mode 100644 vendor/go.uber.org/atomic/float64_ext.go delete mode 100644 vendor/go.uber.org/atomic/gen.go delete mode 100644 vendor/go.uber.org/atomic/int32.go delete mode 100644 vendor/go.uber.org/atomic/int64.go delete mode 100644 vendor/go.uber.org/atomic/nocmp.go delete mode 100644 vendor/go.uber.org/atomic/string.go delete mode 100644 vendor/go.uber.org/atomic/string_ext.go delete mode 100644 vendor/go.uber.org/atomic/uint32.go delete mode 100644 vendor/go.uber.org/atomic/uint64.go delete mode 100644 vendor/go.uber.org/multierr/.travis.yml rename vendor/go.uber.org/{atomic/value.go => multierr/error_post_go120.go} (65%) rename vendor/go.uber.org/multierr/{go113.go => error_pre_go120.go} (66%) delete mode 100644 vendor/go.uber.org/multierr/glide.yaml create mode 100644 vendor/go.uber.org/zap/.golangci.yml delete mode 100644 vendor/go.uber.org/zap/global_prego112.go rename vendor/go.uber.org/{atomic/error_ext.go => zap/internal/level_enabler.go} (65%) rename vendor/go.uber.org/{atomic/error.go => zap/internal/pool/pool.go} (55%) create mode 100644 vendor/go.uber.org/zap/internal/stacktrace/stack.go delete mode 100644 vendor/go.uber.org/zap/stacktrace.go rename vendor/go.uber.org/{atomic/bool_ext.go => zap/zapcore/lazy_with.go} (60%) rename vendor/go.uber.org/zap/{global_go112.go => zapcore/reflected_encoder.go} (64%) create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b_generic.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2b_ref.go create mode 100644 vendor/golang.org/x/crypto/blake2b/blake2x.go create mode 100644 vendor/golang.org/x/crypto/blake2b/register.go create mode 100644 vendor/golang.org/x/crypto/hkdf/hkdf.go create mode 100644 vendor/rsc.io/tmplfunc/LICENSE create mode 100644 vendor/rsc.io/tmplfunc/README.md create mode 100644 vendor/rsc.io/tmplfunc/func.go create mode 100644 vendor/rsc.io/tmplfunc/internal/parse/lex.go create mode 100644 vendor/rsc.io/tmplfunc/internal/parse/node.go create mode 100644 vendor/rsc.io/tmplfunc/internal/parse/parse.go create mode 100644 vendor/rsc.io/tmplfunc/tmpl.go diff --git a/go.mod b/go.mod index aa6f74fa2b3..55965d92a62 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,11 @@ go 1.20 require ( code.cloudfoundry.org/clock v1.0.0 - github.com/IBM/idemix v0.0.0-20220112103229-701e7610d405 + github.com/IBM/idemix v0.0.2-0.20231011101252-a4feda90f3f7 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible github.com/Shopify/sarama v1.20.1 github.com/VictoriaMetrics/fastcache v1.9.0 - github.com/bits-and-blooms/bitset v1.2.1 + github.com/bits-and-blooms/bitset v1.13.0 github.com/cheggaaa/pb v1.0.29 github.com/davecgh/go-spew v1.1.1 github.com/fsouza/go-dockerclient v1.10.0 @@ -29,7 +29,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.1 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 - github.com/spf13/cobra v1.1.3 + github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 github.com/stretchr/testify v1.8.4 // includes ErrorContains @@ -39,8 +39,8 @@ require ( go.etcd.io/etcd/client/pkg/v3 v3.5.9 go.etcd.io/etcd/raft/v3 v3.5.9 go.etcd.io/etcd/server/v3 v3.5.9 - go.uber.org/zap v1.19.0 - golang.org/x/crypto v0.18.0 + go.uber.org/zap v1.26.0 + golang.org/x/crypto v0.19.0 golang.org/x/tools v0.14.0 google.golang.org/grpc v1.61.0 gopkg.in/alecthomas/kingpin.v2 v2.2.6 @@ -55,14 +55,19 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/DataDog/zstd v1.4.5 // indirect - github.com/IBM/mathlib v0.0.0-20220112091634-0a7378db6912 // indirect + github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20231003085036-c4470b87b2d6 // indirect + github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240125153755-b3fcea5c7863 // indirect + github.com/IBM/idemix/bccsp/types v0.0.0-20240125153755-b3fcea5c7863 // indirect + github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/Microsoft/hcsshim v0.11.4 // indirect + github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20230817163708-4b3de6d91874 // indirect github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20210912230133-d1bdfacee922 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/consensys/gnark-crypto v0.6.0 // indirect + github.com/consensys/bavard v0.1.13 // indirect + github.com/consensys/gnark-crypto v0.12.1 // indirect github.com/containerd/containerd v1.6.26 // indirect github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -78,8 +83,9 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/hyperledger/fabric-amcl v0.0.0-20210603140002-2670f91851c8 // indirect + github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.17.6 // indirect github.com/kr/text v0.2.0 // indirect github.com/magiconair/properties v1.8.1 // indirect @@ -99,7 +105,7 @@ require ( github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.8.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.3.1 // indirect github.com/spf13/cast v1.3.1 // indirect @@ -107,15 +113,14 @@ require ( github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect go.etcd.io/etcd/pkg/v3 v3.5.9 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/goleak v1.1.12 // indirect - go.uber.org/multierr v1.6.0 // indirect + go.uber.org/multierr v1.11.0 // indirect golang.org/x/mod v0.15.0 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect gopkg.in/ini.v1 v1.51.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + rsc.io/tmplfunc v0.0.3 // indirect ) diff --git a/go.sum b/go.sum index d34ddfb8b58..c691709b6e4 100644 --- a/go.sum +++ b/go.sum @@ -41,10 +41,16 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= -github.com/IBM/idemix v0.0.0-20220112103229-701e7610d405 h1:7cKDQL0CWDXO9acHJCCc7SUYpMcJ9H9NGVjLvwG66Nc= -github.com/IBM/idemix v0.0.0-20220112103229-701e7610d405/go.mod h1:tBeRCKH37b2OkQRJVomLoYk8OjIMYQm+oRWFiJF0jQI= -github.com/IBM/mathlib v0.0.0-20220112091634-0a7378db6912 h1:rySf+WTiafw7zS7P8GUcZGDd2nDTgLDUx51aIcCFuX4= -github.com/IBM/mathlib v0.0.0-20220112091634-0a7378db6912/go.mod h1:WZGhleRZVSAg25iKkiWXHacTkui2CY1cyJMBOgpQwh8= +github.com/IBM/idemix v0.0.2-0.20231011101252-a4feda90f3f7 h1:ybW6FaLCYGEF03XaR+WJP7bq7XqeBI4Pfj8uKipQT+A= +github.com/IBM/idemix v0.0.2-0.20231011101252-a4feda90f3f7/go.mod h1:74yugcANjVAC9e8wHDmTDvlKHxnPj0V1L9VJ84ExaoU= +github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20231003085036-c4470b87b2d6 h1:vz8YaZRqrdZMeTi6EuIQmtWqhmb6eUxKIJQsWQYAIG8= +github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20231003085036-c4470b87b2d6/go.mod h1:sgvrLB3a8mKr4rX+aBDXPCZBgSRRmQxlyxA3jmwq/Sk= +github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240125153755-b3fcea5c7863 h1:MbN+oydksffkBPsVrPihd6njO/5Byz0f7YEjfOiZIso= +github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240125153755-b3fcea5c7863/go.mod h1:FC0vVgNI6bv8GH0VTwjup+arwJ8Tau1iEhroWZ1oPwU= +github.com/IBM/idemix/bccsp/types v0.0.0-20240125153755-b3fcea5c7863 h1:peYMhPdcC6xSO/3CQ1m2D8QYSNkyMcEbK5HCRIb8Bwk= +github.com/IBM/idemix/bccsp/types v0.0.0-20240125153755-b3fcea5c7863/go.mod h1:IMIJ8WcUpBmV4gcOO/BYKuFYpdXCPYZjpNhFSUlO9b8= +github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da h1:qqGozq4tF6EOVnWoTgBoJGudRKKZXSAYnEtDggzTnsw= +github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da/go.mod h1:Tco9QzE3fQzjMS7nPbHDeFfydAzctStf1Pa8hsh6Hjs= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= @@ -63,6 +69,8 @@ github.com/VictoriaMetrics/fastcache v1.9.0/go.mod h1:otoTS3xu+6IzF/qByjqzjp3rTu github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20230817163708-4b3de6d91874 h1:O08ZCyb1f7UeyOmTeItAw7eSZOlyM0fBnrPgaYgKEiA= +github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20230817163708-4b3de6d91874/go.mod h1:4sHtFlGI84SVjaSW7u1pCfC0bjijd9ZeqbKptU/Qljs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -82,16 +90,15 @@ github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6l github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY= -github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE= +github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -111,9 +118,10 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= -github.com/consensys/bavard v0.1.8-0.20210915155054-088da2f7f54a/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= -github.com/consensys/gnark-crypto v0.6.0 h1:K48rcIJaX2YkQT2k51EiHIxTynpHsOLHF1FVV+0aS7w= -github.com/consensys/gnark-crypto v0.6.0/go.mod h1:PicAZJP763+7N9LZFfj+MquTXq98pwjD6l8Ry8WdHSU= +github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= +github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI= +github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M= +github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/containerd/containerd v1.6.26 h1:VVfrE6ZpyisvB1fzoY8Vkiq4sy+i5oF4uk7zu03RaHs= github.com/containerd/containerd v1.6.26/go.mod h1:I4TRdsdoo5MlKob5khDJS2EPT1l1oMNaE2MBm6FrwxM= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -125,7 +133,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= @@ -305,8 +313,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= -github.com/hyperledger/fabric-amcl v0.0.0-20210603140002-2670f91851c8 h1:BCR8ZlOZ+deUbWxyY6fpoY8LbB7PR5wGGwCTvWQOU2g= -github.com/hyperledger/fabric-amcl v0.0.0-20210603140002-2670f91851c8/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= +github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 h1:B1Nt8hKb//KvgGRprk0h1t4lCnwhE9/ryb1WqfZbV+M= +github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2/go.mod h1:X+DIyUsaTmalOpmpQfIvFZjKHQedrURQ5t4YqquX7lE= github.com/hyperledger/fabric-chaincode-go v0.0.0-20220920210243-7bc6fa0dd58b h1:MGT5rdajc4zbsbU7yMzkLJmsiRwJk5gBX5OdpU117Bg= github.com/hyperledger/fabric-chaincode-go v0.0.0-20220920210243-7bc6fa0dd58b/go.mod h1:OxME3M0bbgoWYHpXIVMzpbXgFqrTZnFmlH0Cpml54m0= github.com/hyperledger/fabric-config v0.1.0 h1:TsR3y5xEoUmXWfp8tcDycjJhVvXEHiV5kfZIxuIte08= @@ -314,7 +322,6 @@ github.com/hyperledger/fabric-config v0.1.0/go.mod h1:aeDZ0moG/qKvwLjddcqYr8+58/ github.com/hyperledger/fabric-lib-go v1.0.0 h1:UL1w7c9LvHZUSkIvHTDGklxFv2kTeva1QI2emOVc324= github.com/hyperledger/fabric-lib-go v1.0.0/go.mod h1:H362nMlunurmHwkYqR5uHL2UDWbQdbfz74n8kbCFsqc= github.com/hyperledger/fabric-protos-go v0.0.0-20200424173316-dd554ba3746e/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= -github.com/hyperledger/fabric-protos-go v0.0.0-20210911123859-041d13f0980c/go.mod h1:xVYTjK4DtZRBxZ2D9aE4y6AbLaPwue2o/criQyQbVD0= github.com/hyperledger/fabric-protos-go v0.2.0 h1:opaGKvsYYD0abMl6ErriNc+CEgLW+ELdKKQ0QyBL7/0= github.com/hyperledger/fabric-protos-go v0.2.0/go.mod h1:WWnyWP40P2roPmmvxsUXSvVI/CF6vwY1K1UFidnKBys= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -336,6 +343,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= +github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -353,7 +362,6 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= -github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= @@ -378,7 +386,6 @@ github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= @@ -509,9 +516,11 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -535,8 +544,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= @@ -559,14 +568,12 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1-0.20210116013205-6990a05d54c2/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/sykesm/zap-logfmt v0.0.2/go.mod h1:TerDJT124HaO8UTpZ2wJCipJRAKQ9XONM1mzUabIh6M= github.com/sykesm/zap-logfmt v0.0.4 h1:U2WzRvmIWG1wDLCFY3sz8UeEmsdHQjHFNlIdmroVFaI= github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= @@ -582,7 +589,6 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= @@ -604,25 +610,17 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= -go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -632,9 +630,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -665,7 +662,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -705,8 +701,6 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= @@ -727,7 +721,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -776,21 +769,19 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420205809-ac73e9fd8988/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -824,7 +815,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -855,7 +845,6 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -973,12 +962,10 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -994,6 +981,7 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU= rsc.io/tmplfunc v0.0.3/go.mod h1:AG3sTPzElb1Io3Yg4voV9AGZJuleGAwaVRxL9M49PhA= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/integration/pluggable/pluggable_suite_test.go b/integration/pluggable/pluggable_suite_test.go index 3fdcc0b80ee..45204990fb3 100644 --- a/integration/pluggable/pluggable_suite_test.go +++ b/integration/pluggable/pluggable_suite_test.go @@ -27,7 +27,9 @@ var ( ) var _ = SynchronizedBeforeSuite(func() []byte { - buildServer = nwo.NewBuildServer() + // need to use the same "generic" build tag for peer as is used for the plugins. + // "generic" build tag on the plugins is a workaround to ensure github.com/kilic/bls12-381 dependency compiles on amd64, see pluggable_test.go compilePlugin() + buildServer = nwo.NewBuildServer("-tags=generic") buildServer.Serve() components = buildServer.Components() diff --git a/integration/pluggable/pluggable_test.go b/integration/pluggable/pluggable_test.go index b2a07329668..dbcd16e2ca8 100644 --- a/integration/pluggable/pluggable_test.go +++ b/integration/pluggable/pluggable_test.go @@ -138,6 +138,7 @@ func compilePlugin(pluginType string) string { "go", "build", "-x", // print build commands while running "-buildmode=plugin", + "-tags=generic", // workaround to ensure github.com/kilic/bls12-381 dependency compiles on amd64 in plugin mode "-o", pluginFilePath, fmt.Sprintf("github.com/hyperledger/fabric/integration/pluggable/testdata/plugins/%s", pluginType), ) diff --git a/vendor/github.com/IBM/idemix/.gitignore b/vendor/github.com/IBM/idemix/.gitignore new file mode 100644 index 00000000000..ba077a4031a --- /dev/null +++ b/vendor/github.com/IBM/idemix/.gitignore @@ -0,0 +1 @@ +bin diff --git a/vendor/github.com/IBM/idemix/CONTRIBUTING.md b/vendor/github.com/IBM/idemix/CONTRIBUTING.md new file mode 100644 index 00000000000..4a5e6798341 --- /dev/null +++ b/vendor/github.com/IBM/idemix/CONTRIBUTING.md @@ -0,0 +1,16 @@ +# Contributing Notes + +## Protobuf Compilation + +There are some internal data structures that are represented as protobufs; the generated code for these are checked in alongside the protos. +They are checked in as this repository is going to be pulled into other executables when it's run hence the files need to be presented. As far +as known there isn't a `pre-build` hook for go to generate the binaries. + + +To regenerate the code + +``` +make genprotos +``` + +This will udpate the files, pulling down and caching any of the tools needed. (this is is in `~/.cache/idemix` should you wish to remove the tools later) \ No newline at end of file diff --git a/vendor/github.com/IBM/idemix/Makefile b/vendor/github.com/IBM/idemix/Makefile index afc6b75203c..e2166644345 100644 --- a/vendor/github.com/IBM/idemix/Makefile +++ b/vendor/github.com/IBM/idemix/Makefile @@ -17,4 +17,21 @@ unit-tests-race: .PHONY: check-deps check-deps: - @go get -u github.com/google/addlicense + @go install github.com/google/addlicense@latest + +.PHONY: idemixgen +idemixgen: + @go install ./tools/idemixgen + +.PHONY: binaries +binaries: + mkdir -p bin/amd64 + GOOS=linux GOARCH=amd64 go build -o bin/amd64/idemixgen tools/idemixgen/main.go + + mkdir -p bin/arm64 + GOOS=darwin GOARCH=arm64 go build -o bin/arm64/idemixgen tools/idemixgen/main.go + +.PHONY: genprotos +genprotos: + go install github.com/bufbuild/buf/cmd/buf@v1.1.1 + buf generate --template buf.gen.yaml diff --git a/vendor/github.com/IBM/idemix/RELEASING.md b/vendor/github.com/IBM/idemix/RELEASING.md new file mode 100644 index 00000000000..3d7f2b9a3aa --- /dev/null +++ b/vendor/github.com/IBM/idemix/RELEASING.md @@ -0,0 +1,13 @@ +# How to release a new version + +- In the github.com ui [Release page](https://github.com/IBM/idemix/releases) click on _'Draft a new release'_ +- Select _'Choose a tag'_ and enter a new tag of the format `v0.0.3` or whatever the next number should be + - note the action workflow later is expecting the tag to start with a 'v' + - this balances some degree of consistency but with flexability to create tags say `v1.0.0-beta-2` + - Please see the [Go notes on module versions](https://go.dev/doc/modules/version-numbers) for more information + - Enter a title - typically something like `Idemix v0.0.3` but no requirements +- The description is free-form - any information on noteable updates can be made. Also the _'generate release notes'_ button is very good at getting a basic changelog. +- Click _'Publish release'_ + +A new release is created, with a tag that can be used in `go get` commands +But also a github action is run to attache the idemix binaries to the release notes automatically. diff --git a/vendor/github.com/IBM/idemix/bccsp/bccsp.go b/vendor/github.com/IBM/idemix/bccsp/bccsp.go index 5a0ac4e277c..0583c9dbed3 100644 --- a/vendor/github.com/IBM/idemix/bccsp/bccsp.go +++ b/vendor/github.com/IBM/idemix/bccsp/bccsp.go @@ -8,11 +8,13 @@ package idemix import ( "reflect" - bccsp "github.com/IBM/idemix/bccsp/schemes" + "github.com/IBM/idemix/bccsp/handlers" + "github.com/IBM/idemix/bccsp/schemes/aries" "github.com/IBM/idemix/bccsp/schemes/dlog/bridge" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + bccsp "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" "github.com/pkg/errors" ) @@ -34,67 +36,309 @@ func New(keyStore bccsp.KeyStore, curve *math.Curve, translator idemix.Translato } // key generators - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerKeyGenOpts{}), &handlers.IssuerKeyGen{Exportable: exportable, Issuer: &bridge.Issuer{Idemix: idmx, Translator: translator}}) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixUserSecretKeyGenOpts{}), &handlers.UserKeyGen{Exportable: exportable, User: &bridge.User{Idemix: idmx, Translator: translator}}) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationKeyGenOpts{}), &handlers.RevocationKeyGen{Exportable: exportable, Revocation: &bridge.Revocation{Idemix: idmx, Translator: translator}}) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerKeyGenOpts{}), + &handlers.IssuerKeyGen{ + Exportable: exportable, + Issuer: &bridge.Issuer{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixUserSecretKeyGenOpts{}), + &handlers.UserKeyGen{ + Exportable: exportable, + User: &bridge.User{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationKeyGenOpts{}), + &handlers.RevocationKeyGen{ + Exportable: exportable, + Revocation: &bridge.Revocation{ + Idemix: idmx, Translator: translator, + }, + }) // key derivers - base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), &handlers.NymKeyDerivation{ - Exportable: exportable, - User: &bridge.User{Idemix: idmx, Translator: translator}, - Translator: translator, - }) + base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), + &handlers.NymKeyDerivation{ + Exportable: exportable, + Translator: translator, + User: &bridge.User{ + Idemix: idmx, Translator: translator, + }, + }) // signers - base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), &userSecreKeySignerMultiplexer{ - signer: &handlers.Signer{SignatureScheme: &bridge.SignatureScheme{Idemix: idmx, Translator: translator}}, - nymSigner: &handlers.NymSigner{NymSignatureScheme: &bridge.NymSignatureScheme{Idemix: idmx, Translator: translator}}, - credentialRequestSigner: &handlers.CredentialRequestSigner{CredRequest: &bridge.CredRequest{Idemix: idmx, Translator: translator}}, - }) - base.AddWrapper(reflect.TypeOf(handlers.NewIssuerSecretKey(nil, true)), &handlers.CredentialSigner{ - Credential: &bridge.Credential{Idemix: idmx, Translator: translator}, - }) - base.AddWrapper(reflect.TypeOf(handlers.NewRevocationSecretKey(nil, true)), &handlers.CriSigner{ - Revocation: &bridge.Revocation{Idemix: idmx, Translator: translator}, - }) + base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), + &userSecreKeySignerMultiplexer{ + signer: &handlers.Signer{ + SignatureScheme: &bridge.SignatureScheme{ + Idemix: idmx, Translator: translator, + }}, + nymSigner: &handlers.NymSigner{ + NymSignatureScheme: &bridge.NymSignatureScheme{ + Idemix: idmx, Translator: translator, + }}, + credentialRequestSigner: &handlers.CredentialRequestSigner{ + CredRequest: &bridge.CredRequest{ + Idemix: idmx, Translator: translator, + }}, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewIssuerSecretKey(nil, true)), + &handlers.CredentialSigner{ + Credential: &bridge.Credential{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewRevocationSecretKey(nil, true)), + &handlers.CriSigner{ + Revocation: &bridge.Revocation{ + Idemix: idmx, Translator: translator, + }, + }) // verifiers - base.AddWrapper(reflect.TypeOf(handlers.NewIssuerPublicKey(nil)), &issuerPublicKeyVerifierMultiplexer{ - verifier: &handlers.Verifier{SignatureScheme: &bridge.SignatureScheme{Idemix: idmx, Translator: translator}}, - credentialRequestVerifier: &handlers.CredentialRequestVerifier{CredRequest: &bridge.CredRequest{Idemix: idmx, Translator: translator}}, - }) - base.AddWrapper(reflect.TypeOf(handlers.NewNymPublicKey(nil, translator)), &handlers.NymVerifier{ - NymSignatureScheme: &bridge.NymSignatureScheme{Idemix: idmx, Translator: translator}, - }) - base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), &handlers.CredentialVerifier{ - Credential: &bridge.Credential{Idemix: idmx, Translator: translator}, - }) - base.AddWrapper(reflect.TypeOf(handlers.NewRevocationPublicKey(nil)), &handlers.CriVerifier{ - Revocation: &bridge.Revocation{Idemix: idmx, Translator: translator}, - }) + base.AddWrapper(reflect.TypeOf(handlers.NewIssuerPublicKey(nil)), + &issuerPublicKeyVerifierMultiplexer{ + verifier: &handlers.Verifier{ + SignatureScheme: &bridge.SignatureScheme{ + Idemix: idmx, Translator: translator, + }}, + credentialRequestVerifier: &handlers.CredentialRequestVerifier{ + CredRequest: &bridge.CredRequest{ + Idemix: idmx, Translator: translator, + }}, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewNymPublicKey(nil, translator)), + &handlers.NymVerifier{ + NymSignatureScheme: &bridge.NymSignatureScheme{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), + &handlers.CredentialVerifier{ + Credential: &bridge.Credential{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewRevocationPublicKey(nil)), + &handlers.CriVerifier{ + Revocation: &bridge.Revocation{ + Idemix: idmx, Translator: translator, + }, + }) // importers - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixUserSecretKeyImportOpts{}), &handlers.UserKeyImporter{ - User: &bridge.User{Idemix: idmx, Translator: translator}, - }) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerPublicKeyImportOpts{}), &handlers.IssuerPublicKeyImporter{ - Issuer: &bridge.Issuer{Idemix: idmx, Translator: translator}, - }) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerKeyImportOpts{}), &handlers.IssuerKeyImporter{ - Issuer: &bridge.Issuer{Idemix: idmx, Translator: translator}, - }) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixNymPublicKeyImportOpts{}), &handlers.NymPublicKeyImporter{ - User: &bridge.User{Idemix: idmx, Translator: translator}, - Translator: translator, - }) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixNymKeyImportOpts{}), &handlers.NymKeyImporter{ - User: &bridge.User{Idemix: idmx, Translator: translator}, - Translator: translator, - }) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationPublicKeyImportOpts{}), &handlers.RevocationPublicKeyImporter{}) - base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationKeyImportOpts{}), &handlers.RevocationKeyImporter{ - Revocation: &bridge.Revocation{Idemix: idmx, Translator: translator}, - }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixUserSecretKeyImportOpts{}), + &handlers.UserKeyImporter{ + Exportable: exportable, + User: &bridge.User{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerPublicKeyImportOpts{}), + &handlers.IssuerPublicKeyImporter{ + Issuer: &bridge.Issuer{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerKeyImportOpts{}), + &handlers.IssuerKeyImporter{ + Exportable: exportable, + Issuer: &bridge.Issuer{ + Idemix: idmx, Translator: translator, + }, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixNymPublicKeyImportOpts{}), + &handlers.NymPublicKeyImporter{ + User: &bridge.User{ + Idemix: idmx, Translator: translator, + }, + Translator: translator, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixNymKeyImportOpts{}), + &handlers.NymKeyImporter{ + Exportable: exportable, + User: &bridge.User{ + Idemix: idmx, Translator: translator, + }, + Translator: translator, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationPublicKeyImportOpts{}), + &handlers.RevocationPublicKeyImporter{}) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationKeyImportOpts{}), + &handlers.RevocationKeyImporter{ + Exportable: exportable, + Revocation: &bridge.Revocation{ + Idemix: idmx, Translator: translator, + }, + }) + + return csp, nil +} + +func NewAries(keyStore bccsp.KeyStore, curve *math.Curve, _translator idemix.Translator, exportable bool) (*csp, error) { + base, err := NewImpl(keyStore) + if err != nil { + return nil, errors.Wrap(err, "failed instantiating base bccsp") + } + + csp := &csp{CSP: base} + + rng, err := curve.Rand() + if err != nil { + return nil, errors.Wrap(err, "failed instantiating PRNG") + } + + // key generators + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerKeyGenOpts{}), + &handlers.IssuerKeyGen{ + Exportable: exportable, + Issuer: &aries.Issuer{}, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixUserSecretKeyGenOpts{}), + &handlers.UserKeyGen{ + Exportable: exportable, + User: &aries.User{ + Curve: curve, + Rng: rng, + }, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationKeyGenOpts{}), + &handlers.RevocationKeyGen{ + Exportable: exportable, + Revocation: &aries.RevocationAuthority{ + Curve: curve, + Rng: rng, + }, + }) + + // key derivers + base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), + &handlers.NymKeyDerivation{ + Exportable: exportable, + Translator: _translator, + User: &aries.User{ + Curve: curve, + Rng: rng, + }, + }) + + // signers + base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), + &userSecreKeySignerMultiplexer{ + signer: &handlers.Signer{ + SignatureScheme: &aries.Signer{ + Curve: curve, + Rng: rng, + }}, + nymSigner: &handlers.NymSigner{ + NymSignatureScheme: &aries.NymSigner{ + Curve: curve, + Rng: rng, + }}, + blindCredentialRequestSigner: &handlers.BlindCredentialRequestSigner{ + CredRequest: &aries.CredRequest{ + Curve: curve, + }}, + credentialRequestSigner: nil, // aries does not implement this approach + }) + base.AddWrapper(reflect.TypeOf(handlers.NewIssuerSecretKey(nil, true)), + &handlers.CredentialSigner{ + Credential: &aries.Cred{ + Curve: curve, + Bls: bbs12381g2pub.New(), + }, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewRevocationSecretKey(nil, true)), + &handlers.CriSigner{ + Revocation: &aries.RevocationAuthority{ + Curve: curve, + Rng: rng, + }, + }) + + // verifiers + base.AddWrapper(reflect.TypeOf(handlers.NewIssuerPublicKey(nil)), + &issuerPublicKeyVerifierMultiplexer{ + verifier: &handlers.Verifier{ + SignatureScheme: &aries.Signer{ + Curve: curve, + Rng: rng, + }}, + blindcredentialRequestVerifier: &handlers.BlindCredentialRequestVerifier{ + CredRequest: &aries.CredRequest{ + Curve: curve, + }}, + credentialRequestVerifier: nil, // aries does not implement this type of issuance + }) + base.AddWrapper(reflect.TypeOf(handlers.NewNymPublicKey(nil, _translator)), + &handlers.NymVerifier{ + NymSignatureScheme: &aries.NymSigner{ + Curve: curve, + Rng: rng, + }, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewUserSecretKey(nil, true)), + &handlers.CredentialVerifier{ + Credential: &aries.Cred{ + Curve: curve, + Bls: bbs12381g2pub.New(), + }, + }) + base.AddWrapper(reflect.TypeOf(handlers.NewRevocationPublicKey(nil)), + &handlers.CriVerifier{ + Revocation: &aries.RevocationAuthority{ + Curve: curve, + Rng: rng, + }, + }) + + // importers + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixUserSecretKeyImportOpts{}), + &handlers.UserKeyImporter{ + Exportable: exportable, + User: &aries.User{ + Curve: curve, + Rng: rng, + }, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerPublicKeyImportOpts{}), + &handlers.IssuerPublicKeyImporter{ + Issuer: &aries.Issuer{}, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixIssuerKeyImportOpts{}), + &handlers.IssuerKeyImporter{ + Exportable: exportable, + Issuer: &aries.Issuer{}, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixNymPublicKeyImportOpts{}), + &handlers.NymPublicKeyImporter{ + User: &aries.User{ + Curve: curve, + Rng: rng, + }, + Translator: _translator, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixNymKeyImportOpts{}), + &handlers.NymKeyImporter{ + Exportable: exportable, + User: &aries.User{ + Curve: curve, + Rng: rng, + }, + Translator: _translator, + }) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationPublicKeyImportOpts{}), + &handlers.RevocationPublicKeyImporter{}) + base.AddWrapper(reflect.TypeOf(&bccsp.IdemixRevocationKeyImportOpts{}), + &handlers.RevocationKeyImporter{ + Exportable: exportable, + Revocation: &aries.RevocationAuthority{ + Curve: curve, + Rng: rng, + }, + }) return csp, nil } @@ -153,9 +397,10 @@ func (csp *csp) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerO } type userSecreKeySignerMultiplexer struct { - signer *handlers.Signer - nymSigner *handlers.NymSigner - credentialRequestSigner *handlers.CredentialRequestSigner + signer *handlers.Signer + nymSigner *handlers.NymSigner + credentialRequestSigner *handlers.CredentialRequestSigner + blindCredentialRequestSigner *handlers.BlindCredentialRequestSigner } func (s *userSecreKeySignerMultiplexer) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { @@ -166,24 +411,31 @@ func (s *userSecreKeySignerMultiplexer) Sign(k bccsp.Key, digest []byte, opts bc return s.nymSigner.Sign(k, digest, opts) case *bccsp.IdemixCredentialRequestSignerOpts: return s.credentialRequestSigner.Sign(k, digest, opts) + case *bccsp.IdemixBlindCredentialRequestSignerOpts: + return s.blindCredentialRequestSigner.Sign(k, digest, opts) default: return nil, errors.New("invalid opts, expected *bccsp.IdemixSignerOpt or *bccsp.IdemixNymSignerOpts or *bccsp.IdemixCredentialRequestSignerOpts") } } type issuerPublicKeyVerifierMultiplexer struct { - verifier *handlers.Verifier - credentialRequestVerifier *handlers.CredentialRequestVerifier + verifier *handlers.Verifier + credentialRequestVerifier *handlers.CredentialRequestVerifier + blindcredentialRequestVerifier *handlers.BlindCredentialRequestVerifier } func (v *issuerPublicKeyVerifierMultiplexer) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { switch opts.(type) { case *bccsp.EidNymAuditOpts: return v.verifier.AuditNymEid(k, signature, digest, opts) + case *bccsp.RhNymAuditOpts: + return v.verifier.AuditNymRh(k, signature, digest, opts) case *bccsp.IdemixSignerOpts: return v.verifier.Verify(k, signature, digest, opts) case *bccsp.IdemixCredentialRequestSignerOpts: return v.credentialRequestVerifier.Verify(k, signature, digest, opts) + case *bccsp.IdemixBlindCredentialRequestSignerOpts: + return v.blindcredentialRequestVerifier.Verify(k, signature, digest, opts) default: return false, errors.New("invalid opts, expected *bccsp.IdemixSignerOpts or *bccsp.IdemixCredentialRequestSignerOpts") } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/cred.go b/vendor/github.com/IBM/idemix/bccsp/handlers/cred.go similarity index 63% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/cred.go rename to vendor/github.com/IBM/idemix/bccsp/handlers/cred.go index cf78abd62b0..740a456bb0f 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/cred.go +++ b/vendor/github.com/IBM/idemix/bccsp/handlers/cred.go @@ -6,14 +6,15 @@ SPDX-License-Identifier: Apache-2.0 package handlers import ( - bccsp "github.com/IBM/idemix/bccsp/schemes" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" "github.com/pkg/errors" ) // CredentialRequestSigner produces credential requests type CredentialRequestSigner struct { // CredRequest implements the underlying cryptographic algorithms - CredRequest CredRequest + CredRequest types.CredRequest } func (c *CredentialRequestSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { @@ -36,10 +37,41 @@ func (c *CredentialRequestSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.Si return c.CredRequest.Sign(userSecretKey.Sk, issuerPK.pk, credentialRequestSignerOpts.IssuerNonce) } +type BlindCredentialRequestSigner struct { + CredRequest types.BlindCredRequest +} + +func (c *BlindCredentialRequestSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { + userSecretKey, ok := k.(*UserSecretKey) + if !ok { + return nil, errors.New("invalid key, expected *userSecretKey") + } + credentialRequestSignerOpts, ok := opts.(*bccsp.IdemixBlindCredentialRequestSignerOpts) + if !ok { + return nil, errors.New("invalid options, expected *IdemixCredentialRequestSignerOpts") + } + if credentialRequestSignerOpts.IssuerPK == nil { + return nil, errors.New("invalid options, missing issuer public key") + } + issuerPK, ok := credentialRequestSignerOpts.IssuerPK.(*issuerPublicKey) + if !ok { + return nil, errors.New("invalid options, expected IssuerPK as *issuerPublicKey") + } + + cred, blinding, err := c.CredRequest.Blind(userSecretKey.Sk, issuerPK.pk, credentialRequestSignerOpts.IssuerNonce) + if err != nil { + return nil, err + } + + credentialRequestSignerOpts.Blinding = blinding + + return cred, err +} + // CredentialRequestVerifier verifies credential requests type CredentialRequestVerifier struct { // CredRequest implements the underlying cryptographic algorithms - CredRequest CredRequest + CredRequest types.CredRequest } func (c *CredentialRequestVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { @@ -60,8 +92,30 @@ func (c *CredentialRequestVerifier) Verify(k bccsp.Key, signature, digest []byte return true, nil } +type BlindCredentialRequestVerifier struct { + CredRequest types.BlindCredRequest +} + +func (c *BlindCredentialRequestVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { + issuerPublicKey, ok := k.(*issuerPublicKey) + if !ok { + return false, errors.New("invalid key, expected *issuerPublicKey") + } + credentialRequestSignerOpts, ok := opts.(*bccsp.IdemixBlindCredentialRequestSignerOpts) + if !ok { + return false, errors.New("invalid options, expected *IdemixCredentialRequestSignerOpts") + } + + err := c.CredRequest.BlindVerify(signature, issuerPublicKey.pk, credentialRequestSignerOpts.IssuerNonce) + if err != nil { + return false, err + } + + return true, nil +} + type CredentialSigner struct { - Credential Credential + Credential types.Credential } func (s *CredentialSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) (signature []byte, err error) { @@ -83,7 +137,7 @@ func (s *CredentialSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpt } type CredentialVerifier struct { - Credential Credential + Credential types.Credential } func (v *CredentialVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (valid bool, err error) { diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/issuer.go b/vendor/github.com/IBM/idemix/bccsp/handlers/issuer.go similarity index 91% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/issuer.go rename to vendor/github.com/IBM/idemix/bccsp/handlers/issuer.go index ce122e4609b..bf925279925 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/issuer.go +++ b/vendor/github.com/IBM/idemix/bccsp/handlers/issuer.go @@ -6,7 +6,8 @@ SPDX-License-Identifier: Apache-2.0 package handlers import ( - bccsp "github.com/IBM/idemix/bccsp/schemes" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" "github.com/pkg/errors" ) @@ -14,12 +15,12 @@ import ( // and implements the bccsp.Key interface type issuerSecretKey struct { // sk is the idemix reference to the issuer key - sk IssuerSecretKey + sk types.IssuerSecretKey // exportable if true, sk can be exported via the Bytes function exportable bool } -func NewIssuerSecretKey(sk IssuerSecretKey, exportable bool) *issuerSecretKey { +func NewIssuerSecretKey(sk types.IssuerSecretKey, exportable bool) *issuerSecretKey { return &issuerSecretKey{sk: sk, exportable: exportable} } @@ -55,10 +56,10 @@ func (k *issuerSecretKey) PublicKey() (bccsp.Key, error) { // issuerPublicKey contains the issuer public key // and implements the bccsp.Key interface type issuerPublicKey struct { - pk IssuerPublicKey + pk types.IssuerPublicKey } -func NewIssuerPublicKey(pk IssuerPublicKey) *issuerPublicKey { +func NewIssuerPublicKey(pk types.IssuerPublicKey) *issuerPublicKey { return &issuerPublicKey{pk} } @@ -88,7 +89,7 @@ type IssuerKeyGen struct { // If a secret key is marked as exportable, its Bytes method will return the key's byte representation. Exportable bool // Issuer implements the underlying cryptographic algorithms - Issuer Issuer + Issuer types.Issuer } func (g *IssuerKeyGen) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { @@ -109,7 +110,7 @@ func (g *IssuerKeyGen) KeyGen(opts bccsp.KeyGenOpts) (k bccsp.Key, err error) { // IssuerPublicKeyImporter imports issuer public keys type IssuerPublicKeyImporter struct { // Issuer implements the underlying cryptographic algorithms - Issuer Issuer + Issuer types.Issuer } func (i *IssuerPublicKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { @@ -141,7 +142,7 @@ type IssuerKeyImporter struct { // If a secret key is marked as exportable, its Bytes method will return the key's byte representation. Exportable bool // Issuer implements the underlying cryptographic algorithms - Issuer Issuer + Issuer types.Issuer } func (i *IssuerKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/nym.go b/vendor/github.com/IBM/idemix/bccsp/handlers/nym.go similarity index 97% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/nym.go rename to vendor/github.com/IBM/idemix/bccsp/handlers/nym.go index 9d7170fd44d..6c35fa41c7c 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/nym.go +++ b/vendor/github.com/IBM/idemix/bccsp/handlers/nym.go @@ -8,8 +8,9 @@ package handlers import ( "crypto/sha256" - bccsp "github.com/IBM/idemix/bccsp/schemes" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/pkg/errors" ) @@ -109,7 +110,7 @@ type NymKeyDerivation struct { // If a secret key is marked as Exportable, its Bytes method will return the key's byte representation. Exportable bool // User implements the underlying cryptographic algorithms - User User + User types.User Translator idemix.Translator } @@ -142,7 +143,7 @@ func (kd *NymKeyDerivation) KeyDeriv(k bccsp.Key, opts bccsp.KeyDerivOpts) (dk b // NymPublicKeyImporter imports nym public keys type NymPublicKeyImporter struct { // User implements the underlying cryptographic algorithms - User User + User types.User Translator idemix.Translator } @@ -169,7 +170,7 @@ func (i *NymPublicKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOp type NymKeyImporter struct { Exportable bool // User implements the underlying cryptographic algorithms - User User + User types.User Translator idemix.Translator } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/nymsigner.go b/vendor/github.com/IBM/idemix/bccsp/handlers/nymsigner.go similarity index 92% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/nymsigner.go rename to vendor/github.com/IBM/idemix/bccsp/handlers/nymsigner.go index 121b85a5a65..f62068d6ba4 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/nymsigner.go +++ b/vendor/github.com/IBM/idemix/bccsp/handlers/nymsigner.go @@ -6,12 +6,13 @@ SPDX-License-Identifier: Apache-2.0 package handlers import ( - bccsp "github.com/IBM/idemix/bccsp/schemes" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" "github.com/pkg/errors" ) type NymSigner struct { - NymSignatureScheme NymSignatureScheme + NymSignatureScheme types.NymSignatureScheme } func (s *NymSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { @@ -56,7 +57,7 @@ func (s *NymSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]b } type NymVerifier struct { - NymSignatureScheme NymSignatureScheme + NymSignatureScheme types.NymSignatureScheme } func (v *NymVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/revocation.go b/vendor/github.com/IBM/idemix/bccsp/handlers/revocation.go similarity index 97% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/revocation.go rename to vendor/github.com/IBM/idemix/bccsp/handlers/revocation.go index 5c43f7a6ae6..ad75f2adb33 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/revocation.go +++ b/vendor/github.com/IBM/idemix/bccsp/handlers/revocation.go @@ -14,7 +14,8 @@ import ( "fmt" "reflect" - bccsp "github.com/IBM/idemix/bccsp/schemes" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" "github.com/pkg/errors" ) @@ -123,7 +124,7 @@ type RevocationKeyGen struct { // If a secret key is marked as exportable, its Bytes method will return the key's byte representation. Exportable bool // Revocation implements the underlying cryptographic algorithms - Revocation Revocation + Revocation types.Revocation } func (g *RevocationKeyGen) KeyGen(opts bccsp.KeyGenOpts) (bccsp.Key, error) { @@ -172,7 +173,7 @@ type RevocationKeyImporter struct { // If a secret key is marked as exportable, its Bytes method will return the key's byte representation. Exportable bool // Revocation implements the underlying cryptographic algorithms - Revocation Revocation + Revocation types.Revocation } func (i *RevocationKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { @@ -197,7 +198,7 @@ func (i *RevocationKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportO } type CriSigner struct { - Revocation Revocation + Revocation types.Revocation } func (s *CriSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { @@ -219,7 +220,7 @@ func (s *CriSigner) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]b } type CriVerifier struct { - Revocation Revocation + Revocation types.Revocation } func (v *CriVerifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/signer.go b/vendor/github.com/IBM/idemix/bccsp/handlers/signer.go similarity index 69% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/signer.go rename to vendor/github.com/IBM/idemix/bccsp/handlers/signer.go index eb167cf8eee..bd0e76b694d 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/signer.go +++ b/vendor/github.com/IBM/idemix/bccsp/handlers/signer.go @@ -6,12 +6,15 @@ SPDX-License-Identifier: Apache-2.0 package handlers import ( - bccsp "github.com/IBM/idemix/bccsp/schemes" + "crypto/ecdsa" "github.com/pkg/errors" + + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" ) type Signer struct { - SignatureScheme SignatureScheme + SignatureScheme types.SignatureScheme } func (s *Signer) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte, error) { @@ -46,7 +49,8 @@ func (s *Signer) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte sigma, meta, err := s.SignatureScheme.Sign( signerOpts.Credential, userSecretKey.Sk, - nymSk.Pk, nymSk.Sk, + nymSk.Pk, + nymSk.Sk, ipk.pk, signerOpts.Attributes, digest, @@ -54,6 +58,7 @@ func (s *Signer) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte signerOpts.EidIndex, signerOpts.CRI, signerOpts.SigType, + signerOpts.Metadata, ) if err != nil { return nil, err @@ -65,7 +70,7 @@ func (s *Signer) Sign(k bccsp.Key, digest []byte, opts bccsp.SignerOpts) ([]byte } type Verifier struct { - SignatureScheme SignatureScheme + SignatureScheme types.SignatureScheme } func (v *Verifier) AuditNymEid(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { @@ -89,6 +94,37 @@ func (v *Verifier) AuditNymEid(k bccsp.Key, signature, digest []byte, opts bccsp signature, signerOpts.EnrollmentID, signerOpts.RNymEid, + signerOpts.AuditVerificationType, + ) + if err != nil { + return false, err + } + + return true, nil +} + +func (v *Verifier) AuditNymRh(k bccsp.Key, signature, digest []byte, opts bccsp.SignerOpts) (bool, error) { + issuerPublicKey, ok := k.(*issuerPublicKey) + if !ok { + return false, errors.New("invalid key, expected *issuerPublicKey") + } + + signerOpts, ok := opts.(*bccsp.RhNymAuditOpts) + if !ok { + return false, errors.New("invalid options, expected *RhNymAuditOpts") + } + + if len(signature) == 0 { + return false, errors.New("invalid signature, it must not be empty") + } + + err := v.SignatureScheme.AuditNymRh( + issuerPublicKey.pk, + signerOpts.RhIndex, + signature, + signerOpts.RevocationHandle, + signerOpts.RNymRh, + signerOpts.AuditVerificationType, ) if err != nil { return false, err @@ -108,15 +144,18 @@ func (v *Verifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.Sign return false, errors.New("invalid options, expected *IdemixSignerOpts") } - rpk, ok := signerOpts.RevocationPublicKey.(*revocationPublicKey) - if !ok { - return false, errors.New("invalid options, expected *revocationPublicKey") + var rPK *ecdsa.PublicKey + if signerOpts.RevocationPublicKey != nil { + revocationPK, ok := signerOpts.RevocationPublicKey.(*revocationPublicKey) + if !ok { + return false, errors.New("invalid options, expected *revocationPublicKey") + } + rPK = revocationPK.pubKey } if len(signature) == 0 { return false, errors.New("invalid signature, it must not be empty") } - err := v.SignatureScheme.Verify( issuerPublicKey.pk, signature, @@ -124,7 +163,7 @@ func (v *Verifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.Sign signerOpts.Attributes, signerOpts.RhIndex, signerOpts.EidIndex, - rpk.pubKey, + rPK, signerOpts.Epoch, signerOpts.VerificationType, signerOpts.Metadata, @@ -132,6 +171,5 @@ func (v *Verifier) Verify(k bccsp.Key, signature, digest []byte, opts bccsp.Sign if err != nil { return false, err } - return true, nil } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/user.go b/vendor/github.com/IBM/idemix/bccsp/handlers/user.go similarity index 95% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/user.go rename to vendor/github.com/IBM/idemix/bccsp/handlers/user.go index af4b6c32362..34295f77949 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/user.go +++ b/vendor/github.com/IBM/idemix/bccsp/handlers/user.go @@ -8,7 +8,8 @@ package handlers import ( "crypto/sha256" - bccsp "github.com/IBM/idemix/bccsp/schemes" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/pkg/errors" ) @@ -57,7 +58,7 @@ type UserKeyGen struct { // If a secret key is marked as Exportable, its Bytes method will return the key's byte representation. Exportable bool // User implements the underlying cryptographic algorithms - User User + User types.User } func (g *UserKeyGen) KeyGen(opts bccsp.KeyGenOpts) (bccsp.Key, error) { @@ -75,7 +76,7 @@ type UserKeyImporter struct { // If a secret key is marked as Exportable, its Bytes method will return the key's byte representation. Exportable bool // User implements the underlying cryptographic algorithms - User User + User types.User } func (i *UserKeyImporter) KeyImport(raw interface{}, opts bccsp.KeyImportOpts) (k bccsp.Key, err error) { diff --git a/vendor/github.com/IBM/idemix/bccsp/impl.go b/vendor/github.com/IBM/idemix/bccsp/impl.go index 65cd225e2dd..7b92c189d2c 100644 --- a/vendor/github.com/IBM/idemix/bccsp/impl.go +++ b/vendor/github.com/IBM/idemix/bccsp/impl.go @@ -1,11 +1,10 @@ /* Copyright IBM Corp. 2016 All Rights Reserved. - Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, @@ -19,7 +18,7 @@ import ( "hash" "reflect" - bccsp "github.com/IBM/idemix/bccsp/schemes" + bccsp "github.com/IBM/idemix/bccsp/types" "github.com/IBM/idemix/common/flogging" "github.com/pkg/errors" ) diff --git a/vendor/github.com/IBM/idemix/bccsp/keystore/dummy.go b/vendor/github.com/IBM/idemix/bccsp/keystore/dummy.go index ec7d944de8a..c00003833f4 100644 --- a/vendor/github.com/IBM/idemix/bccsp/keystore/dummy.go +++ b/vendor/github.com/IBM/idemix/bccsp/keystore/dummy.go @@ -9,7 +9,7 @@ package keystore import ( "errors" - bccsp "github.com/IBM/idemix/bccsp/schemes" + bccsp "github.com/IBM/idemix/bccsp/types" ) // Dummy is a read-only KeyStore that neither loads nor stores keys. diff --git a/vendor/github.com/IBM/idemix/bccsp/keystore/kvsbased.go b/vendor/github.com/IBM/idemix/bccsp/keystore/kvsbased.go index 20e7593290c..f15eff41a48 100644 --- a/vendor/github.com/IBM/idemix/bccsp/keystore/kvsbased.go +++ b/vendor/github.com/IBM/idemix/bccsp/keystore/kvsbased.go @@ -9,10 +9,10 @@ package keystore import ( "encoding/hex" - bccsp "github.com/IBM/idemix/bccsp/schemes" + "github.com/IBM/idemix/bccsp/handlers" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" "github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + bccsp "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/pkg/errors" ) diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/LICENSE b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/blind_sign.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/blind_sign.go new file mode 100644 index 00000000000..3478e76b4d4 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/blind_sign.go @@ -0,0 +1,202 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package aries + +import ( + "crypto/rand" + "errors" + "fmt" + + ml "github.com/IBM/mathlib" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" +) + +// BlindedMessages represents a set of messages prepared +// (blinded) to be submitted to a signer for a blind signature. +type BlindedMessages struct { + PK *bbs12381g2pub.PublicKeyWithGenerators + S *ml.Zr + C *ml.G1 + PoK *POKOfBlindedMessages +} + +func (b *BlindedMessages) Bytes() []byte { + bytes := make([]byte, 0) + + bytes = append(bytes, b.C.Compressed()...) + bytes = append(bytes, b.PoK.C.Compressed()...) + bytes = append(bytes, b.PoK.ProofC.ToBytes()...) + + return bytes +} + +func ParseBlindedMessages(bytes []byte, curve *ml.Curve) (*BlindedMessages, error) { + offset := 0 + + C, err := curve.NewG1FromCompressed(bytes[offset : offset+curve.CompressedG1ByteSize]) + if err != nil { + return nil, fmt.Errorf("parse G1 point (C): %w", err) + } + + offset += curve.CompressedG1ByteSize + + PoKC, err := curve.NewG1FromCompressed(bytes[offset : offset+curve.CompressedG1ByteSize]) + if err != nil { + return nil, fmt.Errorf("parse G1 point (PoKC): %w", err) + } + + offset += curve.CompressedG1ByteSize + + proof, err := bbs12381g2pub.ParseProofG1(bytes[offset:]) + if err != nil { + return nil, fmt.Errorf("parse G1 proof: %w", err) + } + + return &BlindedMessages{ + C: C, + PoK: &POKOfBlindedMessages{ + C: PoKC, + ProofC: proof, + }, + }, nil +} + +// POKOfBlindedMessages is the zero-knowledge proof that the +// requester knows the messages they have submitted for blind +// signature in the form of a Pedersen commitment. +type POKOfBlindedMessages struct { + C *ml.G1 + ProofC *bbs12381g2pub.ProofG1 +} + +// VerifyProof verifies the correctness of the zero knowledge +// proof against the supplied commitment, challenge and public key. +func (b *POKOfBlindedMessages) VerifyProof(messages []bool, commitment *ml.G1, challenge *ml.Zr, PK *bbs12381g2pub.PublicKey) error { + pubKeyWithGenerators, err := PK.ToPublicKeyWithGenerators(len(messages)) + if err != nil { + return fmt.Errorf("build generators from public key: %w", err) + } + + bases := []*ml.G1{pubKeyWithGenerators.H0} + + for i, in := range messages { + if !in { + continue + } + + bases = append(bases, pubKeyWithGenerators.H[i]) + } + + err = b.ProofC.Verify(bases, commitment, challenge) + if err != nil { + return errors.New("invalid proof") + } + + return nil +} + +// VerifyBlinding verifies that `msgCommit` is a valid +// commitment of a set of messages against the appropriate bases. +func VerifyBlinding(messageBitmap []bool, msgCommit *ml.G1, bmProof *POKOfBlindedMessages, PK *bbs12381g2pub.PublicKey, nonce []byte) error { + challengeBytes := msgCommit.Bytes() + challengeBytes = append(challengeBytes, bmProof.C.Bytes()...) + challengeBytes = append(challengeBytes, nonce...) + + return bmProof.VerifyProof(messageBitmap, msgCommit, bbs12381g2pub.FrFromOKM(challengeBytes), PK) +} + +// BlindMessages constructs a commitment to a set of messages +// that need to be blinded before signing, and generates the +// corresponding ZKP. +func BlindMessages(messages [][]byte, PK *bbs12381g2pub.PublicKey, blindedMsgCount int, nonce []byte, curve *ml.Curve) (*BlindedMessages, error) { + zrs := make([]*ml.Zr, len(messages)) + + for i, msg := range messages { + if len(msg) == 0 { + continue + } + + zrs[i] = bbs12381g2pub.FrFromOKM(msg) + } + + return BlindMessagesZr(zrs, PK, blindedMsgCount, nonce, curve) +} + +// BlindMessagesZr constructs a commitment to a set of messages +// that need to be blinded before signing, and generates the +// corresponding ZKP. +func BlindMessagesZr(zrs []*ml.Zr, PK *bbs12381g2pub.PublicKey, blindedMsgCount int, nonce []byte, curve *ml.Curve) (*BlindedMessages, error) { + pubKeyWithGenerators, err := PK.ToPublicKeyWithGenerators(len(zrs)) + if err != nil { + return nil, fmt.Errorf("build generators from public key: %w", err) + } + + commit := bbs12381g2pub.NewProverCommittingG1() + cb := bbs12381g2pub.NewCommitmentBuilder(blindedMsgCount + 1) + secrets := make([]*ml.Zr, 0, blindedMsgCount+1) + + s := curve.NewRandomZr(rand.Reader) + + commit.Commit(pubKeyWithGenerators.H0) + cb.Add(pubKeyWithGenerators.H0, s) + secrets = append(secrets, s) + + for i, zr := range zrs { + if zr == nil { + continue + } + + commit.Commit(pubKeyWithGenerators.H[i]) + cb.Add(pubKeyWithGenerators.H[i], zr) + secrets = append(secrets, zr) + } + + C := cb.Build() + U := commit.Finish() + + challengeBytes := C.Bytes() + challengeBytes = append(challengeBytes, U.Commitment.Bytes()...) + challengeBytes = append(challengeBytes, nonce...) + + return &BlindedMessages{ + PK: pubKeyWithGenerators, + S: s, + C: C, + PoK: &POKOfBlindedMessages{ + C: U.Commitment, + ProofC: U.GenerateProof(bbs12381g2pub.FrFromOKM(challengeBytes), secrets), + }, + }, nil +} + +// BlindSign signs disclosed and blinded messages using private key in compressed form. +func BlindSign(messages []*bbs12381g2pub.SignatureMessage, msgCount int, commitment *ml.G1, privKeyBytes []byte) ([]byte, error) { + privKey, err := bbs12381g2pub.UnmarshalPrivateKey(privKeyBytes) + if err != nil { + return nil, fmt.Errorf("unmarshal private key: %w", err) + } + + if len(messages) == 0 { + return nil, errors.New("messages are not defined") + } + + bbs := bbs12381g2pub.New() + + return bbs.SignWithKeyFr(messages, msgCount, commitment, privKey) +} + +// UnblindSign converts a signature over some blind messages into a standard signature. +func UnblindSign(sigBytes []byte, S *ml.Zr, curve *ml.Curve) ([]byte, error) { + signature, err := bbs12381g2pub.ParseSignature(sigBytes) + if err != nil { + return nil, fmt.Errorf("parse signature: %w", err) + } + + signature.S = curve.ModAdd(signature.S, S, curve.GroupOrder) + + return signature.ToBytes() +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.go new file mode 100644 index 00000000000..a2659a74ff8 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.go @@ -0,0 +1,109 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package aries + +import ( + "fmt" + + "github.com/IBM/idemix/bccsp/types" + math "github.com/IBM/mathlib" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" + "github.com/golang/protobuf/proto" + "github.com/pkg/errors" +) + +type Cred struct { + Bls *bbs12381g2pub.BBSG2Pub + Curve *math.Curve +} + +// Sign issues a new credential, which is the last step of the interactive issuance protocol +// All attribute values are added by the issuer at this step and then signed together with a commitment to +// the user's secret key from a credential request +func (c *Cred) Sign(key types.IssuerSecretKey, credentialRequest []byte, attributes []types.IdemixAttribute) ([]byte, error) { + isk, ok := key.(*IssuerSecretKey) + if !ok { + return nil, errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", key) + } + + blindedMsg, err := ParseBlindedMessages(credentialRequest, c.Curve) + if err != nil { + return nil, fmt.Errorf("ParseBlindedMessages failed [%w]", err) + } + + msgsZr := attributesToSignatureMessage(nil, attributes, c.Curve) + + sig, err := BlindSign(msgsZr, len(attributes)+1, blindedMsg.C, isk.SK.FR.Bytes()) + if err != nil { + return nil, fmt.Errorf("ParseBlindedMessages failed [%w]", err) + } + + attrs := make([][]byte, len(attributes)) + for i, msg := range msgsZr { + attrs[i] = msg.FR.Bytes() + } + + cred := &Credential{ + Cred: sig, + Attrs: attrs, + } + + credBytes, err := proto.Marshal(cred) + if err != nil { + return nil, fmt.Errorf("proto.Marshal failed [%w]", err) + } + + return credBytes, nil +} + +// Verify cryptographically verifies the credential by verifying the signature +// on the attribute values and user's secret key +func (c *Cred) Verify(sk *math.Zr, key types.IssuerPublicKey, credBytes []byte, attributes []types.IdemixAttribute) error { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + credential := &Credential{} + err := proto.Unmarshal(credBytes, credential) + if err != nil { + return fmt.Errorf("proto.Unmarshal failed [%w]", err) + } + + sigma, err := bbs12381g2pub.ParseSignature(credential.Cred) + if err != nil { + return fmt.Errorf("ParseSignature failed [%w]", err) + } + + sm := make([]*bbs12381g2pub.SignatureMessage, len(credential.Attrs)+1) + sm[0] = &bbs12381g2pub.SignatureMessage{ + FR: sk, + Idx: 0, + } + for i, v := range credential.Attrs { + sm[i+1] = &bbs12381g2pub.SignatureMessage{ + FR: c.Curve.NewZrFromBytes(v), + Idx: i + 1, + } + + switch attributes[i].Type { + case types.IdemixHiddenAttribute: + continue + case types.IdemixBytesAttribute: + fr := bbs12381g2pub.FrFromOKM(attributes[i].Value.([]byte)) + if !fr.Equals(sm[i+1].FR) { + return errors.Errorf("credential does not contain the correct attribute value at position [%d]", i) + } + case types.IdemixIntAttribute: + fr := c.Curve.NewZrFromInt(int64(attributes[i].Value.(int))) + if !fr.Equals(sm[i+1].FR) { + return errors.Errorf("credential does not contain the correct attribute value at position [%d]", i) + } + } + } + + return sigma.Verify(sm, ipk.PKwG) +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.pb.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.pb.go new file mode 100644 index 00000000000..c56551e2c33 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.pb.go @@ -0,0 +1,433 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: bccsp/schemes/aries/cred.proto + +package aries + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// Credential specifies a credential object +type Credential struct { + Cred []byte `protobuf:"bytes,1,opt,name=cred,proto3" json:"cred,omitempty"` + Attrs [][]byte `protobuf:"bytes,2,rep,name=attrs,proto3" json:"attrs,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Credential) Reset() { *m = Credential{} } +func (m *Credential) String() string { return proto.CompactTextString(m) } +func (*Credential) ProtoMessage() {} +func (*Credential) Descriptor() ([]byte, []int) { + return fileDescriptor_57701eac61520cf0, []int{0} +} + +func (m *Credential) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Credential.Unmarshal(m, b) +} +func (m *Credential) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Credential.Marshal(b, m, deterministic) +} +func (m *Credential) XXX_Merge(src proto.Message) { + xxx_messageInfo_Credential.Merge(m, src) +} +func (m *Credential) XXX_Size() int { + return xxx_messageInfo_Credential.Size(m) +} +func (m *Credential) XXX_DiscardUnknown() { + xxx_messageInfo_Credential.DiscardUnknown(m) +} + +var xxx_messageInfo_Credential proto.InternalMessageInfo + +func (m *Credential) GetCred() []byte { + if m != nil { + return m.Cred + } + return nil +} + +func (m *Credential) GetAttrs() [][]byte { + if m != nil { + return m.Attrs + } + return nil +} + +// Signature is a PoK of a BBS+ signature (a credential) +type Signature struct { + MainSignature []byte `protobuf:"bytes,1,opt,name=main_signature,json=mainSignature,proto3" json:"main_signature,omitempty"` + Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + Nym []byte `protobuf:"bytes,3,opt,name=nym,proto3" json:"nym,omitempty"` + NymProof []byte `protobuf:"bytes,4,opt,name=nym_proof,json=nymProof,proto3" json:"nym_proof,omitempty"` + NymEid []byte `protobuf:"bytes,5,opt,name=nym_eid,json=nymEid,proto3" json:"nym_eid,omitempty"` + NymEidProof []byte `protobuf:"bytes,6,opt,name=nym_eid_proof,json=nymEidProof,proto3" json:"nym_eid_proof,omitempty"` + NymEidIdx int32 `protobuf:"varint,7,opt,name=nym_eid_idx,json=nymEidIdx,proto3" json:"nym_eid_idx,omitempty"` + NymRh []byte `protobuf:"bytes,8,opt,name=nym_rh,json=nymRh,proto3" json:"nym_rh,omitempty"` + NymRhProof []byte `protobuf:"bytes,9,opt,name=nym_rh_proof,json=nymRhProof,proto3" json:"nym_rh_proof,omitempty"` + NymRhIdx int32 `protobuf:"varint,10,opt,name=nym_rh_idx,json=nymRhIdx,proto3" json:"nym_rh_idx,omitempty"` + RevocationEpochPk []byte `protobuf:"bytes,11,opt,name=revocation_epoch_pk,json=revocationEpochPk,proto3" json:"revocation_epoch_pk,omitempty"` + RevocationPkSig []byte `protobuf:"bytes,12,opt,name=revocation_pk_sig,json=revocationPkSig,proto3" json:"revocation_pk_sig,omitempty"` + Epoch int64 `protobuf:"varint,13,opt,name=epoch,proto3" json:"epoch,omitempty"` + NonRevocationProof *NonRevocationProof `protobuf:"bytes,14,opt,name=non_revocation_proof,json=nonRevocationProof,proto3" json:"non_revocation_proof,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Signature) Reset() { *m = Signature{} } +func (m *Signature) String() string { return proto.CompactTextString(m) } +func (*Signature) ProtoMessage() {} +func (*Signature) Descriptor() ([]byte, []int) { + return fileDescriptor_57701eac61520cf0, []int{1} +} + +func (m *Signature) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Signature.Unmarshal(m, b) +} +func (m *Signature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Signature.Marshal(b, m, deterministic) +} +func (m *Signature) XXX_Merge(src proto.Message) { + xxx_messageInfo_Signature.Merge(m, src) +} +func (m *Signature) XXX_Size() int { + return xxx_messageInfo_Signature.Size(m) +} +func (m *Signature) XXX_DiscardUnknown() { + xxx_messageInfo_Signature.DiscardUnknown(m) +} + +var xxx_messageInfo_Signature proto.InternalMessageInfo + +func (m *Signature) GetMainSignature() []byte { + if m != nil { + return m.MainSignature + } + return nil +} + +func (m *Signature) GetNonce() []byte { + if m != nil { + return m.Nonce + } + return nil +} + +func (m *Signature) GetNym() []byte { + if m != nil { + return m.Nym + } + return nil +} + +func (m *Signature) GetNymProof() []byte { + if m != nil { + return m.NymProof + } + return nil +} + +func (m *Signature) GetNymEid() []byte { + if m != nil { + return m.NymEid + } + return nil +} + +func (m *Signature) GetNymEidProof() []byte { + if m != nil { + return m.NymEidProof + } + return nil +} + +func (m *Signature) GetNymEidIdx() int32 { + if m != nil { + return m.NymEidIdx + } + return 0 +} + +func (m *Signature) GetNymRh() []byte { + if m != nil { + return m.NymRh + } + return nil +} + +func (m *Signature) GetNymRhProof() []byte { + if m != nil { + return m.NymRhProof + } + return nil +} + +func (m *Signature) GetNymRhIdx() int32 { + if m != nil { + return m.NymRhIdx + } + return 0 +} + +func (m *Signature) GetRevocationEpochPk() []byte { + if m != nil { + return m.RevocationEpochPk + } + return nil +} + +func (m *Signature) GetRevocationPkSig() []byte { + if m != nil { + return m.RevocationPkSig + } + return nil +} + +func (m *Signature) GetEpoch() int64 { + if m != nil { + return m.Epoch + } + return 0 +} + +func (m *Signature) GetNonRevocationProof() *NonRevocationProof { + if m != nil { + return m.NonRevocationProof + } + return nil +} + +// NonRevocationProof contains proof that the credential is not revoked +type NonRevocationProof struct { + RevocationAlg int32 `protobuf:"varint,1,opt,name=revocation_alg,json=revocationAlg,proto3" json:"revocation_alg,omitempty"` + NonRevocationProof []byte `protobuf:"bytes,2,opt,name=non_revocation_proof,json=nonRevocationProof,proto3" json:"non_revocation_proof,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NonRevocationProof) Reset() { *m = NonRevocationProof{} } +func (m *NonRevocationProof) String() string { return proto.CompactTextString(m) } +func (*NonRevocationProof) ProtoMessage() {} +func (*NonRevocationProof) Descriptor() ([]byte, []int) { + return fileDescriptor_57701eac61520cf0, []int{2} +} + +func (m *NonRevocationProof) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NonRevocationProof.Unmarshal(m, b) +} +func (m *NonRevocationProof) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NonRevocationProof.Marshal(b, m, deterministic) +} +func (m *NonRevocationProof) XXX_Merge(src proto.Message) { + xxx_messageInfo_NonRevocationProof.Merge(m, src) +} +func (m *NonRevocationProof) XXX_Size() int { + return xxx_messageInfo_NonRevocationProof.Size(m) +} +func (m *NonRevocationProof) XXX_DiscardUnknown() { + xxx_messageInfo_NonRevocationProof.DiscardUnknown(m) +} + +var xxx_messageInfo_NonRevocationProof proto.InternalMessageInfo + +func (m *NonRevocationProof) GetRevocationAlg() int32 { + if m != nil { + return m.RevocationAlg + } + return 0 +} + +func (m *NonRevocationProof) GetNonRevocationProof() []byte { + if m != nil { + return m.NonRevocationProof + } + return nil +} + +type CredentialRevocationInformation struct { + // epoch contains the epoch (time window) in which this CRI is valid + Epoch int64 `protobuf:"varint,1,opt,name=epoch,proto3" json:"epoch,omitempty"` + // epoch_pk is the public key that is used by the revocation authority in this epoch + EpochPk []byte `protobuf:"bytes,2,opt,name=epoch_pk,json=epochPk,proto3" json:"epoch_pk,omitempty"` + // epoch_pk_sig is a signature on the EpochPK valid under the revocation authority's long term key + EpochPkSig []byte `protobuf:"bytes,3,opt,name=epoch_pk_sig,json=epochPkSig,proto3" json:"epoch_pk_sig,omitempty"` + // revocation_alg denotes which revocation algorithm is used + RevocationAlg int32 `protobuf:"varint,4,opt,name=revocation_alg,json=revocationAlg,proto3" json:"revocation_alg,omitempty"` + // revocation_data contains data specific to the revocation algorithm used + RevocationData []byte `protobuf:"bytes,5,opt,name=revocation_data,json=revocationData,proto3" json:"revocation_data,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *CredentialRevocationInformation) Reset() { *m = CredentialRevocationInformation{} } +func (m *CredentialRevocationInformation) String() string { return proto.CompactTextString(m) } +func (*CredentialRevocationInformation) ProtoMessage() {} +func (*CredentialRevocationInformation) Descriptor() ([]byte, []int) { + return fileDescriptor_57701eac61520cf0, []int{3} +} + +func (m *CredentialRevocationInformation) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_CredentialRevocationInformation.Unmarshal(m, b) +} +func (m *CredentialRevocationInformation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_CredentialRevocationInformation.Marshal(b, m, deterministic) +} +func (m *CredentialRevocationInformation) XXX_Merge(src proto.Message) { + xxx_messageInfo_CredentialRevocationInformation.Merge(m, src) +} +func (m *CredentialRevocationInformation) XXX_Size() int { + return xxx_messageInfo_CredentialRevocationInformation.Size(m) +} +func (m *CredentialRevocationInformation) XXX_DiscardUnknown() { + xxx_messageInfo_CredentialRevocationInformation.DiscardUnknown(m) +} + +var xxx_messageInfo_CredentialRevocationInformation proto.InternalMessageInfo + +func (m *CredentialRevocationInformation) GetEpoch() int64 { + if m != nil { + return m.Epoch + } + return 0 +} + +func (m *CredentialRevocationInformation) GetEpochPk() []byte { + if m != nil { + return m.EpochPk + } + return nil +} + +func (m *CredentialRevocationInformation) GetEpochPkSig() []byte { + if m != nil { + return m.EpochPkSig + } + return nil +} + +func (m *CredentialRevocationInformation) GetRevocationAlg() int32 { + if m != nil { + return m.RevocationAlg + } + return 0 +} + +func (m *CredentialRevocationInformation) GetRevocationData() []byte { + if m != nil { + return m.RevocationData + } + return nil +} + +type NymSignature struct { + MainSignature []byte `protobuf:"bytes,1,opt,name=main_signature,json=mainSignature,proto3" json:"main_signature,omitempty"` + Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *NymSignature) Reset() { *m = NymSignature{} } +func (m *NymSignature) String() string { return proto.CompactTextString(m) } +func (*NymSignature) ProtoMessage() {} +func (*NymSignature) Descriptor() ([]byte, []int) { + return fileDescriptor_57701eac61520cf0, []int{4} +} + +func (m *NymSignature) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_NymSignature.Unmarshal(m, b) +} +func (m *NymSignature) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_NymSignature.Marshal(b, m, deterministic) +} +func (m *NymSignature) XXX_Merge(src proto.Message) { + xxx_messageInfo_NymSignature.Merge(m, src) +} +func (m *NymSignature) XXX_Size() int { + return xxx_messageInfo_NymSignature.Size(m) +} +func (m *NymSignature) XXX_DiscardUnknown() { + xxx_messageInfo_NymSignature.DiscardUnknown(m) +} + +var xxx_messageInfo_NymSignature proto.InternalMessageInfo + +func (m *NymSignature) GetMainSignature() []byte { + if m != nil { + return m.MainSignature + } + return nil +} + +func (m *NymSignature) GetNonce() []byte { + if m != nil { + return m.Nonce + } + return nil +} + +func init() { + proto.RegisterType((*Credential)(nil), "aries.Credential") + proto.RegisterType((*Signature)(nil), "aries.Signature") + proto.RegisterType((*NonRevocationProof)(nil), "aries.NonRevocationProof") + proto.RegisterType((*CredentialRevocationInformation)(nil), "aries.CredentialRevocationInformation") + proto.RegisterType((*NymSignature)(nil), "aries.NymSignature") +} + +func init() { proto.RegisterFile("bccsp/schemes/aries/cred.proto", fileDescriptor_57701eac61520cf0) } + +var fileDescriptor_57701eac61520cf0 = []byte{ + // 553 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x94, 0x41, 0x8b, 0xd3, 0x40, + 0x14, 0xc7, 0x49, 0xd3, 0xb4, 0xcd, 0x6b, 0xba, 0xba, 0x63, 0xc5, 0x2c, 0xca, 0x1a, 0x0a, 0x62, + 0xf5, 0xd0, 0x88, 0x82, 0xf7, 0x56, 0x17, 0x29, 0xcb, 0x2e, 0x21, 0x7b, 0x59, 0x44, 0x08, 0xd3, + 0x64, 0xb6, 0x1d, 0xda, 0x99, 0x09, 0x49, 0x2a, 0xcd, 0xd7, 0xf1, 0xe8, 0xe7, 0xf0, 0xe4, 0xc7, + 0xf0, 0xb8, 0x9f, 0x42, 0x66, 0x26, 0x35, 0x81, 0xd6, 0xdb, 0x9e, 0x32, 0xef, 0xff, 0x7b, 0xf3, + 0xef, 0xbc, 0xf7, 0x66, 0x0a, 0xe7, 0x8b, 0x38, 0xce, 0x53, 0x3f, 0x8f, 0x57, 0x84, 0x91, 0xdc, + 0xc7, 0x19, 0x25, 0xb9, 0x1f, 0x67, 0x24, 0x99, 0xa4, 0x99, 0x28, 0x04, 0xb2, 0x94, 0x32, 0xfa, + 0x08, 0xf0, 0x29, 0x23, 0x09, 0xe1, 0x05, 0xc5, 0x1b, 0x84, 0xa0, 0x2d, 0x53, 0x5c, 0xc3, 0x33, + 0xc6, 0x4e, 0xa8, 0xd6, 0x68, 0x08, 0x16, 0x2e, 0x8a, 0x2c, 0x77, 0x5b, 0x9e, 0x39, 0x76, 0x42, + 0x1d, 0x8c, 0xee, 0x4d, 0xb0, 0x6f, 0xe8, 0x92, 0xe3, 0x62, 0x9b, 0x11, 0xf4, 0x0a, 0x4e, 0x18, + 0xa6, 0x3c, 0xca, 0xf7, 0x4a, 0xe5, 0x30, 0x90, 0x6a, 0x9d, 0x36, 0x04, 0x8b, 0x0b, 0x1e, 0x13, + 0xb7, 0xa5, 0xa8, 0x0e, 0xd0, 0x63, 0x30, 0x79, 0xc9, 0x5c, 0x53, 0x69, 0x72, 0x89, 0x9e, 0x83, + 0xcd, 0x4b, 0x16, 0xa5, 0x99, 0x10, 0x77, 0x6e, 0x5b, 0xe9, 0x3d, 0x5e, 0xb2, 0x40, 0xc6, 0xe8, + 0x19, 0x74, 0x25, 0x24, 0x34, 0x71, 0x2d, 0x85, 0x3a, 0xbc, 0x64, 0x17, 0x34, 0x41, 0x23, 0x18, + 0x54, 0xa0, 0xda, 0xd9, 0x51, 0xb8, 0xaf, 0xb1, 0xde, 0x7c, 0x0e, 0xfd, 0x7d, 0x0e, 0x4d, 0x76, + 0x6e, 0xd7, 0x33, 0xc6, 0x56, 0x68, 0xeb, 0x8c, 0x79, 0xb2, 0x43, 0x4f, 0x41, 0xba, 0x45, 0xd9, + 0xca, 0xed, 0x55, 0x47, 0x2c, 0x59, 0xb8, 0x42, 0x1e, 0x38, 0x5a, 0xae, 0x9c, 0x6d, 0x05, 0x41, + 0x41, 0x6d, 0xfc, 0x02, 0xa0, 0xca, 0x90, 0xbe, 0xa0, 0x7c, 0x7b, 0x8a, 0x4b, 0xdb, 0x09, 0x3c, + 0xc9, 0xc8, 0x77, 0x11, 0xe3, 0x82, 0x0a, 0x1e, 0x91, 0x54, 0xc4, 0xab, 0x28, 0x5d, 0xbb, 0x7d, + 0x65, 0x73, 0x5a, 0xa3, 0x0b, 0x49, 0x82, 0x35, 0x7a, 0x0b, 0x0d, 0x31, 0x4a, 0xd7, 0xb2, 0xb1, + 0xae, 0xa3, 0xb2, 0x1f, 0xd5, 0x20, 0x58, 0xdf, 0xd0, 0xa5, 0x6c, 0xaa, 0x32, 0x74, 0x07, 0x9e, + 0x31, 0x36, 0x43, 0x1d, 0xa0, 0x4b, 0x18, 0x72, 0xc1, 0xa3, 0xa6, 0x8b, 0x3a, 0xf9, 0x89, 0x67, + 0x8c, 0xfb, 0xef, 0xcf, 0x26, 0x6a, 0xfa, 0x93, 0x6b, 0xc1, 0xc3, 0xda, 0x4e, 0x26, 0x84, 0x88, + 0x1f, 0x68, 0x23, 0x06, 0xe8, 0x30, 0x53, 0x0e, 0xbd, 0x61, 0x8f, 0x37, 0x4b, 0x35, 0x74, 0x2b, + 0x1c, 0xd4, 0xea, 0x74, 0xb3, 0x44, 0xef, 0xfe, 0x73, 0x12, 0x7d, 0x07, 0x8e, 0xfd, 0xdc, 0x2f, + 0x03, 0x5e, 0xd6, 0x97, 0xb2, 0xa6, 0x73, 0x7e, 0x27, 0x32, 0xa6, 0x96, 0x75, 0xd5, 0x46, 0xb3, + 0xea, 0x33, 0xe8, 0xfd, 0x6b, 0xae, 0xf6, 0xef, 0x92, 0xaa, 0xa5, 0x1e, 0x38, 0x7b, 0xa4, 0xba, + 0xa9, 0xaf, 0x1b, 0x54, 0x58, 0x36, 0xf2, 0xb0, 0x9e, 0xf6, 0xb1, 0x7a, 0x5e, 0x43, 0x63, 0x04, + 0x51, 0x82, 0x0b, 0x5c, 0xdd, 0xc3, 0xc6, 0xee, 0xcf, 0xb8, 0xc0, 0xa3, 0x4b, 0x70, 0xae, 0x4b, + 0xf6, 0x30, 0x8f, 0x64, 0xb6, 0x05, 0x3b, 0x16, 0x4c, 0x8f, 0x6d, 0x66, 0xcb, 0xee, 0x04, 0xf2, + 0x19, 0x07, 0xc6, 0xd7, 0x37, 0x4b, 0x5a, 0xac, 0xb6, 0x8b, 0x49, 0x2c, 0x98, 0x3f, 0x9f, 0x5d, + 0xf9, 0x34, 0x21, 0x8c, 0xee, 0xfc, 0x23, 0xcf, 0xff, 0x47, 0xcb, 0x9c, 0xde, 0xde, 0xfe, 0x6c, + 0x59, 0x53, 0x19, 0xfd, 0xae, 0xbe, 0x7f, 0x5a, 0xa7, 0xea, 0xfb, 0xed, 0x4b, 0x30, 0xbb, 0x22, + 0x05, 0x96, 0x15, 0xdd, 0x57, 0x6c, 0xd1, 0x51, 0x7f, 0x16, 0x1f, 0xfe, 0x06, 0x00, 0x00, 0xff, + 0xff, 0x2e, 0xc8, 0xaa, 0x1d, 0x4e, 0x04, 0x00, 0x00, +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.proto b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.proto new file mode 100644 index 00000000000..17a120fe525 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/cred.proto @@ -0,0 +1,65 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +syntax = "proto3"; + +option go_package = "github.com/IBM/idemix/bccsp/schemes/aries"; + +package aries; + +// Credential specifies a credential object +message Credential { + bytes cred = 1; + repeated bytes attrs = 2; +} + +// Signature is a PoK of a BBS+ signature (a credential) +message Signature { + bytes main_signature = 1; + bytes nonce = 2; + bytes nym = 3; + bytes nym_proof = 4; + bytes nym_eid = 5; + bytes nym_eid_proof = 6; + int32 nym_eid_idx = 7; + bytes nym_rh = 8; + bytes nym_rh_proof = 9; + int32 nym_rh_idx = 10; + + bytes revocation_epoch_pk = 11; + bytes revocation_pk_sig = 12; + int64 epoch = 13; + + NonRevocationProof non_revocation_proof = 14; +} + +// NonRevocationProof contains proof that the credential is not revoked +message NonRevocationProof { + int32 revocation_alg = 1; + bytes non_revocation_proof = 2; +} + +message CredentialRevocationInformation { + // epoch contains the epoch (time window) in which this CRI is valid + int64 epoch = 1; + + // epoch_pk is the public key that is used by the revocation authority in this epoch + bytes epoch_pk = 2; + + // epoch_pk_sig is a signature on the EpochPK valid under the revocation authority's long term key + bytes epoch_pk_sig = 3; + + // revocation_alg denotes which revocation algorithm is used + int32 revocation_alg = 4; + + // revocation_data contains data specific to the revocation algorithm used + bytes revocation_data = 5; +} + +message NymSignature { + bytes main_signature = 1; + bytes nonce = 2; +} \ No newline at end of file diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/credrequest.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/credrequest.go new file mode 100644 index 00000000000..fbe54c47a36 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/credrequest.go @@ -0,0 +1,76 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package aries + +import ( + "fmt" + + "github.com/IBM/idemix/bccsp/types" + math "github.com/IBM/mathlib" + "github.com/golang/protobuf/proto" + "github.com/pkg/errors" +) + +type CredRequest struct { + Curve *math.Curve +} + +// Sign creates a new Credential Request, the first message of the interactive credential issuance protocol +// (from user to issuer) +func (c *CredRequest) Blind(sk *math.Zr, key types.IssuerPublicKey, nonce []byte) ([]byte, []byte, error) { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return nil, nil, errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + zrs := make([]*math.Zr, ipk.N+1) + zrs[UserSecretKeyIndex] = sk + + blindedMsg, err := BlindMessagesZr(zrs, ipk.PK, 1, nonce, c.Curve) + if err != nil { + return nil, nil, fmt.Errorf("BlindMessagesZr failed [%w]", err) + } + + return blindedMsg.Bytes(), blindedMsg.S.Bytes(), nil +} + +// Verify verifies the credential request +func (c *CredRequest) BlindVerify(credRequest []byte, key types.IssuerPublicKey, nonce []byte) error { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + bitmap := make([]bool, ipk.N+1) + bitmap[UserSecretKeyIndex] = true + + blindedMsg, err := ParseBlindedMessages(credRequest, c.Curve) + if err != nil { + return fmt.Errorf("ParseBlindedMessages failed [%w]", err) + } + + return VerifyBlinding(bitmap, blindedMsg.C, blindedMsg.PoK, ipk.PK, nonce) +} + +// Unblind takes a blinded signature and a blinding and produces a standard signature +func (c *CredRequest) Unblind(signature, blinding []byte) ([]byte, error) { + S := c.Curve.NewZrFromBytes(blinding) + + credential := &Credential{} + err := proto.Unmarshal(signature, credential) + if err != nil { + return nil, fmt.Errorf("proto.Unmarshal failed [%w]", err) + } + + sig, err := UnblindSign(credential.Cred, S, c.Curve) + if err != nil { + return nil, fmt.Errorf("bls.UnblindSign failed [%w]", err) + } + + credential.Cred = sig + + return proto.Marshal(credential) +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/issuer.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/issuer.go new file mode 100644 index 00000000000..bc935aeb473 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/issuer.go @@ -0,0 +1,134 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package aries + +import ( + "crypto/rand" + "crypto/sha256" + "fmt" + + "github.com/IBM/idemix/bccsp/types" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" +) + +// TODO: +// * expose curve from aries so we can use always that curve + +// UserSecretKeyIndex is the index of `sk` among the attributes +const UserSecretKeyIndex = 0 + +// IssuerPublicKey is the issuer public key +type IssuerPublicKey struct { + PK *bbs12381g2pub.PublicKey + PKwG *bbs12381g2pub.PublicKeyWithGenerators + // N is the number of attributes; it *does not* include the user secret key + N int +} + +// Bytes returns the byte representation of this key +func (i *IssuerPublicKey) Bytes() ([]byte, error) { + return i.PK.Marshal() +} + +// Hash returns the hash representation of this key. +// The output is supposed to be collision-resistant +func (i *IssuerPublicKey) Hash() []byte { + return i.PK.PointG2.Compressed() +} + +// IssuerPublicKey is the issuer secret key +type IssuerSecretKey struct { + IssuerPublicKey + SK *bbs12381g2pub.PrivateKey +} + +// Bytes returns the byte representation of this key +func (i *IssuerSecretKey) Bytes() ([]byte, error) { + return i.SK.Marshal() +} + +// Public returns the corresponding public key +func (i *IssuerSecretKey) Public() types.IssuerPublicKey { + return &i.IssuerPublicKey +} + +// Issuer is a local interface to decouple from the idemix implementation +type Issuer struct { +} + +// NewKey generates a new idemix issuer key w.r.t the passed attribute names. +func (i *Issuer) NewKey(AttributeNames []string) (types.IssuerSecretKey, error) { + seed := make([]byte, 32) + + _, err := rand.Read(seed) + if err != nil { + return nil, fmt.Errorf("rand.Read failed [%w]", err) + } + + PK, SK, err := bbs12381g2pub.GenerateKeyPair(sha256.New, seed) + if err != nil { + return nil, fmt.Errorf("GenerateKeyPair failed [%w]", err) + } + + PKwG, err := PK.ToPublicKeyWithGenerators(len(AttributeNames) + 1) + if err != nil { + return nil, fmt.Errorf("ToPublicKeyWithGenerators failed [%w]", err) + } + + return &IssuerSecretKey{ + SK: SK, + IssuerPublicKey: IssuerPublicKey{ + PK: PK, + PKwG: PKwG, + N: len(AttributeNames), + }, + }, nil +} + +// NewPublicKeyFromBytes converts the passed bytes to an Issuer key +// It makes sure that the so obtained key has the passed attributes, if specified +func (i *Issuer) NewKeyFromBytes(raw []byte, attributes []string) (types.IssuerSecretKey, error) { + SK, err := bbs12381g2pub.UnmarshalPrivateKey(raw) + if err != nil { + return nil, fmt.Errorf("UnmarshalPrivateKey failed [%w]", err) + } + + PK := SK.PublicKey() + + PKwG, err := PK.ToPublicKeyWithGenerators(len(attributes) + 1) + if err != nil { + return nil, fmt.Errorf("ToPublicKeyWithGenerators failed [%w]", err) + } + + return &IssuerSecretKey{ + SK: SK, + IssuerPublicKey: IssuerPublicKey{ + PK: PK, + PKwG: PKwG, + N: len(attributes), + }, + }, nil +} + +// NewPublicKeyFromBytes converts the passed bytes to an Issuer public key +// It makes sure that the so obtained public key has the passed attributes, if specified +func (i *Issuer) NewPublicKeyFromBytes(raw []byte, attributes []string) (types.IssuerPublicKey, error) { + PK, err := bbs12381g2pub.UnmarshalPublicKey(raw) + if err != nil { + return nil, fmt.Errorf("UnmarshalPublicKey failed [%w]", err) + } + + PKwG, err := PK.ToPublicKeyWithGenerators(len(attributes) + 1) + if err != nil { + return nil, fmt.Errorf("ToPublicKeyWithGenerators failed [%w]", err) + } + + return &IssuerPublicKey{ + PK: PK, + PKwG: PKwG, + N: len(attributes), + }, nil +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/nymsigner.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/nymsigner.go new file mode 100644 index 00000000000..69c7fe98243 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/nymsigner.go @@ -0,0 +1,102 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package aries + +import ( + "fmt" + "io" + + "github.com/IBM/idemix/bccsp/types" + math "github.com/IBM/mathlib" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" + "github.com/golang/protobuf/proto" +) + +const nymSigLabel = "nym-sig" + +type NymSigner struct { + Curve *math.Curve + Rng io.Reader +} + +// Sign creates a new idemix pseudonym signature +func (s *NymSigner) Sign( + sk *math.Zr, + Nym *math.G1, + RNym *math.Zr, + key types.IssuerPublicKey, + digest []byte, +) ([]byte, error) { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return nil, fmt.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + Nonce := s.Curve.NewRandomZr(s.Rng) + + commit := bbs12381g2pub.NewProverCommittingG1() + commit.Commit(ipk.PKwG.H0) + commit.Commit(ipk.PKwG.H[0]) + commitNym := commit.Finish() + + challengeBytes := []byte(nymSigLabel) + challengeBytes = append(challengeBytes, Nym.Bytes()...) + challengeBytes = append(challengeBytes, commitNym.ToBytes()...) + challengeBytes = append(challengeBytes, digest...) + + proofChallenge := bbs12381g2pub.FrFromOKM(challengeBytes) + + challengeBytes = proofChallenge.Bytes() + challengeBytes = append(challengeBytes, Nonce.Bytes()...) + proofChallenge = bbs12381g2pub.FrFromOKM(challengeBytes) + + proof := commitNym.GenerateProof(proofChallenge, []*math.Zr{RNym, sk}) + + sig := &NymSignature{ + MainSignature: proof.ToBytes(), + Nonce: Nonce.Bytes(), + } + + return proto.Marshal(sig) +} + +// Verify verifies an idemix NymSignature +func (s *NymSigner) Verify( + key types.IssuerPublicKey, + Nym *math.G1, + sigBytes, digest []byte, +) error { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return fmt.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + sig := &NymSignature{} + err := proto.Unmarshal(sigBytes, sig) + if err != nil { + return fmt.Errorf("error unmarshalling signature: [%w]", err) + } + + nymProof, err := bbs12381g2pub.ParseProofG1(sig.MainSignature) + if err != nil { + return fmt.Errorf("parse nym proof: %w", err) + } + + challengeBytes := []byte(nymSigLabel) + challengeBytes = append(challengeBytes, Nym.Bytes()...) + challengeBytes = append(challengeBytes, ipk.PKwG.H0.Bytes()...) + challengeBytes = append(challengeBytes, ipk.PKwG.H[0].Bytes()...) + challengeBytes = append(challengeBytes, nymProof.Commitment.Bytes()...) + challengeBytes = append(challengeBytes, digest...) + + proofChallenge := bbs12381g2pub.FrFromOKM(challengeBytes) + + challengeBytes = proofChallenge.Bytes() + challengeBytes = append(challengeBytes, sig.Nonce...) + proofChallenge = bbs12381g2pub.FrFromOKM(challengeBytes) + + return nymProof.Verify([]*math.G1{ipk.PKwG.H0, ipk.PKwG.H[0]}, Nym, proofChallenge) +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/revocation.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/revocation.go new file mode 100644 index 00000000000..053de7ad265 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/revocation.go @@ -0,0 +1,124 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package aries + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "encoding/asn1" + "fmt" + "io" + "math/big" + + weakbb "github.com/IBM/idemix/bccsp/schemes/weak-bb" + "github.com/IBM/idemix/bccsp/types" + math "github.com/IBM/mathlib" + "github.com/golang/protobuf/proto" + "github.com/pkg/errors" +) + +type RevocationAuthority struct { + Rng io.Reader + Curve *math.Curve +} + +// NewKey generates a long term signing key that will be used for revocation +func (r *RevocationAuthority) NewKey() (*ecdsa.PrivateKey, error) { + return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) +} + +// NewKeyFromBytes generates a long term signing key that will be used for revocation from the passed bytes +func (r *RevocationAuthority) NewKeyFromBytes(raw []byte) (*ecdsa.PrivateKey, error) { + priv := &ecdsa.PrivateKey{} + priv.D = new(big.Int).SetBytes(raw) + priv.PublicKey.Curve = elliptic.P384() + priv.PublicKey.X, priv.PublicKey.Y = elliptic.P384().ScalarBaseMult(priv.D.Bytes()) + + return priv, nil +} + +// Sign creates the Credential Revocation Information for a certain time period (epoch). +// Users can use the CRI to prove that they are not revoked. +func (r *RevocationAuthority) Sign(key *ecdsa.PrivateKey, _ [][]byte, epoch int, alg types.RevocationAlgorithm) ([]byte, error) { + if key == nil { + return nil, errors.Errorf("CreateCRI received nil input") + } + + cri := &CredentialRevocationInformation{} + cri.RevocationAlg = int32(alg) + cri.Epoch = int64(epoch) + + if alg == types.AlgNoRevocation { + // put a dummy PK in the proto + cri.EpochPk = r.Curve.GenG2.Bytes() + } else { + // create epoch key + _, epochPk := weakbb.WbbKeyGen(r.Curve, r.Rng) + cri.EpochPk = epochPk.Bytes() + } + + // sign epoch + epoch key with long term key + bytesToSign, err := proto.Marshal(cri) + if err != nil { + return nil, errors.Wrap(err, "failed to marshal CRI") + } + + digest := sha256.Sum256(bytesToSign) + + cri.EpochPkSig, err = key.Sign(rand.Reader, digest[:], nil) + if err != nil { + return nil, err + } + + if alg == types.AlgNoRevocation { + return proto.Marshal(cri) + } else { + return nil, errors.Errorf("the specified revocation algorithm is not supported.") + } +} + +// Verify verifies that the revocation PK for a certain epoch is valid, +// by checking that it was signed with the long term revocation key. +// Note that even if we use no revocation (i.e., alg = ALG_NO_REVOCATION), we need +// to verify the signature to make sure the issuer indeed signed that no revocation +// is used in this epoch. +func (r *RevocationAuthority) Verify(pk *ecdsa.PublicKey, criRaw []byte, epoch int, alg types.RevocationAlgorithm) error { + if pk == nil { + return fmt.Errorf("CreateCRI received nil input") + } + + cri := &CredentialRevocationInformation{} + err := proto.Unmarshal(criRaw, cri) + if err != nil { + return err + } + + epochPkSig := cri.EpochPkSig + cri.EpochPkSig = nil + cri.Epoch = int64(epoch) + cri.RevocationAlg = int32(alg) + + bytesToVer, err := proto.Marshal(cri) + if err != nil { + return err + } + + digest := sha256.Sum256(bytesToVer) + + var sig struct{ R, S *big.Int } + if _, err := asn1.Unmarshal(epochPkSig, &sig); err != nil { + return errors.Wrap(err, "failed unmashalling signature") + } + + if !ecdsa.Verify(pk, digest[:], sig.R, sig.S) { + return errors.Errorf("EpochPKSig invalid") + } + + return nil +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/signer.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/signer.go new file mode 100644 index 00000000000..c7601402e62 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/signer.go @@ -0,0 +1,794 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ +package aries + +import ( + "crypto/ecdsa" + "fmt" + "io" + + "github.com/IBM/idemix/bccsp/types" + math "github.com/IBM/mathlib" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" + "github.com/golang/protobuf/proto" +) + +// AttributeIndexInNym is the index of the blinding factor of the attribute in a Nym commitment +const AttributeIndexInNym = 1 + +// IndexOffsetVC2Attributes is the index of the attributes in VC2 +const IndexOffsetVC2Attributes = 2 + +const signLabel = "sign" +const signWithEidNymLabel = "signWithEidNym" +const signWithEidNymRhNymLabel = "signWithEidNymRhNym" // When the revocation handle is present the enrollment id must also be present + +type Signer struct { + Curve *math.Curve + Rng io.Reader +} + +func (s *Signer) getPoKOfSignature( + credBytes []byte, + attributes []types.IdemixAttribute, + sk *math.Zr, + ipk *bbs12381g2pub.PublicKeyWithGenerators, +) (*bbs12381g2pub.PoKOfSignature, []*bbs12381g2pub.SignatureMessage, error) { + credential := &Credential{} + err := proto.Unmarshal(credBytes, credential) + if err != nil { + return nil, nil, fmt.Errorf("proto.Unmarshal failed [%w]", err) + } + + signature, err := bbs12381g2pub.ParseSignature(credential.Cred) + if err != nil { + return nil, nil, fmt.Errorf("parse signature: %w", err) + } + + messagesFr := credential.toSignatureMessage(sk, s.Curve) + + pokOS, err := bbs12381g2pub.NewPoKOfSignature(signature, messagesFr, revealedAttributesIndex(attributes), ipk) + if err != nil { + return nil, nil, fmt.Errorf("bbs12381g2pub.NewPoKOfSignature error: %w", err) + } + + return pokOS, messagesFr, nil +} + +func (s *Signer) getChallengeHash( + pokSignature *bbs12381g2pub.PoKOfSignature, + Nym *math.G1, + commitNym *math.G1, + eid *attributeCommitment, + rh *attributeCommitment, + msg []byte, + sigType types.SignatureType, +) (*math.Zr, *math.Zr) { + + // hash the signature type first + var challengeBytes []byte + switch sigType { + case types.Standard: + challengeBytes = []byte(signLabel) + case types.EidNym: + challengeBytes = []byte(signWithEidNymLabel) + case types.EidNymRhNym: + challengeBytes = []byte(signWithEidNymRhNymLabel) + default: + panic("programming error") + } + + // hash the main proof + challengeBytes = append(challengeBytes, pokSignature.ToBytes()...) + + // hash the Nym and t-value + challengeBytes = append(challengeBytes, Nym.Bytes()...) + challengeBytes = append(challengeBytes, commitNym.Bytes()...) + + // hash the NymEid and t-value + if sigType == types.EidNym || sigType == types.EidNymRhNym { + challengeBytes = append(challengeBytes, eid.comm.Bytes()...) + challengeBytes = append(challengeBytes, eid.proof.Commitment.Bytes()...) + } + + // hash the NymEid and t-value + if sigType == types.EidNymRhNym { + challengeBytes = append(challengeBytes, rh.comm.Bytes()...) + challengeBytes = append(challengeBytes, rh.proof.Commitment.Bytes()...) + } + + // hash the nonce + proofNonce := bbs12381g2pub.ParseProofNonce(msg) + proofNonceBytes := proofNonce.ToBytes() + challengeBytes = append(challengeBytes, proofNonceBytes...) + + c := bbs12381g2pub.FrFromOKM(challengeBytes) + + Nonce := s.Curve.NewRandomZr(s.Rng) + + challengeBytes = c.Bytes() + challengeBytes = append(challengeBytes, Nonce.Bytes()...) + + return bbs12381g2pub.FrFromOKM(challengeBytes), Nonce +} + +func (s *Signer) packageProof( + attributes []types.IdemixAttribute, + Nym *math.G1, + proof *bbs12381g2pub.PoKOfSignatureProof, + proofNym *bbs12381g2pub.ProofG1, + nymEid *attributeCommitment, + proofNymEid *bbs12381g2pub.ProofG1, + rhNym *attributeCommitment, + proofRhNym *bbs12381g2pub.ProofG1, + cri *CredentialRevocationInformation, + nonce *math.Zr, +) ([]byte, error) { + payload := bbs12381g2pub.NewPoKPayload(len(attributes)+1, revealedAttributesIndex(attributes)) + + payloadBytes, err := payload.ToBytes() + if err != nil { + return nil, fmt.Errorf("derive proof: paylod to bytes: %w", err) + } + + signatureProofBytes := append(payloadBytes, proof.ToBytes()...) + + sig := &Signature{ + MainSignature: signatureProofBytes, + Nonce: nonce.Bytes(), + Nym: Nym.Bytes(), + NymProof: proofNym.ToBytes(), + RevocationEpochPk: cri.EpochPk, + RevocationPkSig: cri.EpochPkSig, + Epoch: cri.Epoch, + NonRevocationProof: &NonRevocationProof{ + RevocationAlg: cri.RevocationAlg, + }, + } + + if nymEid != nil { + sig.NymEid = nymEid.comm.Bytes() + sig.NymEidProof = proofNymEid.ToBytes() + sig.NymEidIdx = int32(nymEid.index) + } + + if rhNym != nil { + sig.NymRh = rhNym.comm.Bytes() + sig.NymRhProof = proofRhNym.ToBytes() + sig.NymRhIdx = int32(rhNym.index) + } + + return proto.Marshal(sig) +} + +func (s *Signer) getCommitNym( + ipk *IssuerPublicKey, + pokSignature *bbs12381g2pub.PoKOfSignature, +) *bbs12381g2pub.ProverCommittedG1 { + + // Nym is H0^{RNym} \cdot H[0]^{sk} + + commit := bbs12381g2pub.NewProverCommittingG1() + commit.Commit(ipk.PKwG.H0) + commit.Commit(ipk.PKwG.H[UserSecretKeyIndex]) + // we force the same blinding factor used in PokVC2 to prove equality. + // 1) commit.BlindingFactors[1] is the blinding factor for the sk in the Nym + // H0^{RNym} \cdot H[0]^{sk} + // 2) pokSignature.PokVC2.BlindingFactors[2] is the blinding factor for the sk in + // D * (-r3~) + Q_1 * s~ + H_j1 * m~_j1 + ... + H_jU * m~_jU + // index 0 is for D, index 1 is for s~ and index 2 is for the first message (which is the sk) + commit.BlindingFactors[AttributeIndexInNym] = pokSignature.PokVC2.BlindingFactors[IndexOffsetVC2Attributes+UserSecretKeyIndex] + + return commit.Finish() +} + +type attributeCommitment struct { + index int + proof *bbs12381g2pub.ProverCommittedG1 + comm *math.G1 + r *math.Zr +} + +func safeRhNymAuditDataAccess(metadata *types.IdemixSignerMetadata) *types.AttrNymAuditData { + if metadata == nil { + return nil + } + + return metadata.RhNymAuditData +} + +func rhAttrCommitmentEnabled(sigType types.SignatureType) bool { + return sigType == types.EidNymRhNym +} + +func safeNymEidAuditDataAccess(metadata *types.IdemixSignerMetadata) *types.AttrNymAuditData { + if metadata == nil { + return nil + } + + return metadata.EidNymAuditData +} + +func nymEidAttrCommitmentEnabled(sigType types.SignatureType) bool { + return sigType != types.Standard +} + +func (s *Signer) getAttributeCommitment( + ipk *IssuerPublicKey, + pokSignature *bbs12381g2pub.PoKOfSignature, + attr *math.Zr, + idxInBases int, + enabled bool, + auditData *types.AttrNymAuditData, +) (*attributeCommitment, error) { + + if !enabled { + return nil, nil + } + + var Nym *math.G1 + var R *math.Zr + + cb := bbs12381g2pub.NewCommitmentBuilder(2) + + if auditData != nil { + if !attr.Equals(auditData.Attr) { + return nil, fmt.Errorf("attribute supplied in metadata differs from signed") + } + + R = auditData.Rand + + cb.Add(ipk.PKwG.H0, R) + cb.Add(ipk.PKwG.H[idxInBases], auditData.Attr) + Nym = cb.Build() + + if !auditData.Nym.Equals(Nym) { + return nil, fmt.Errorf("nym supplied in metadata cannot be recomputed") + } + } else { + R = s.Curve.NewRandomZr(s.Rng) + + cb.Add(ipk.PKwG.H0, R) + cb.Add(ipk.PKwG.H[idxInBases], attr) + Nym = cb.Build() + } + + attrIndexInCommitment, err := s.indexOfAttributeInCommitment(pokSignature.PokVC2, idxInBases, ipk.PKwG) + if err != nil { + return nil, fmt.Errorf("error determining index for attribute: %w", err) + } + + commit := bbs12381g2pub.NewProverCommittingG1() + commit.Commit(ipk.PKwG.H0) + commit.Commit(ipk.PKwG.H[idxInBases]) + + // we force the same blinding factor used in PokVC2 to prove equality. + commit.BlindingFactors[AttributeIndexInNym] = pokSignature.PokVC2.BlindingFactors[attrIndexInCommitment] + + return &attributeCommitment{ + index: attrIndexInCommitment, + proof: commit.Finish(), + comm: Nym, + r: R, + }, nil +} + +func (s *Signer) indexOfAttributeInCommitment( + c *bbs12381g2pub.ProverCommittedG1, + indexInPk int, + ipk *bbs12381g2pub.PublicKeyWithGenerators, +) (int, error) { + + // this is the base used in the public key for the attribute; no +1 since we assume that the caller has already catered for that + base := ipk.H[indexInPk] + + for i, h_i := range c.Bases { + if base.Equals(h_i) { + return i, nil + } + } + + return -1, fmt.Errorf("attribute not found") +} + +// Sign creates a new idemix signature +func (s *Signer) Sign( + credBytes []byte, + sk *math.Zr, + Nym *math.G1, + RNym *math.Zr, + key types.IssuerPublicKey, + attributes []types.IdemixAttribute, + msg []byte, + rhIndex, eidIndex int, + criRaw []byte, + sigType types.SignatureType, + metadata *types.IdemixSignerMetadata, +) ([]byte, *types.IdemixSignerMetadata, error) { + + /////////////// + // arg check // + /////////////// + + if sigType == types.EidNym && + attributes[eidIndex].Type != types.IdemixHiddenAttribute { + return nil, nil, fmt.Errorf("cannot create idemix signature: disclosure of enrollment ID requested for EidNym signature") + } + + if sigType == types.EidNymRhNym && + (attributes[eidIndex].Type != types.IdemixHiddenAttribute || + attributes[rhIndex].Type != types.IdemixHiddenAttribute) { + return nil, nil, fmt.Errorf("cannot create idemix signature: disclosure of enrollment ID or RH requested for EidNymRhNym signature") + } + + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return nil, nil, fmt.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + /////////////////////// + // handle revocation // + /////////////////////// + + cri := &CredentialRevocationInformation{} + err := proto.Unmarshal(criRaw, cri) + if err != nil { + return nil, nil, fmt.Errorf("failed unmarshalling credential revocation information [%w]", err) + } + + // if we add any other revocation algorithm, we need to change the challenge hash + if cri.RevocationAlg != int32(types.AlgNoRevocation) { + return nil, nil, fmt.Errorf("Unsupported revocation algorithm") + } + + ////////////////////////////////// + // Generate main PoK (1st move) // + ////////////////////////////////// + + pokSignature, messagesFr, err := s.getPoKOfSignature(credBytes, attributes, sk, ipk.PKwG) + if err != nil { + return nil, nil, err + } + + ////////////////// + // Handling Nym // + ////////////////// + + commitNym := s.getCommitNym(ipk, pokSignature) + + /////////////////// + // Handle NymEID // + /////////////////// + + // increment the index to cater for the first hidden index for `sk` + eidIndex++ + + nymEid, err := s.getAttributeCommitment(ipk, pokSignature, messagesFr[eidIndex].FR, eidIndex, nymEidAttrCommitmentEnabled(sigType), safeNymEidAuditDataAccess(metadata)) + if err != nil { + return nil, nil, err + } + + /////////////////// + // Handle RhNym // + /////////////////// + + // increment the index to cater for the first hidden index for `sk` + rhIndex++ + + rhNym, err := s.getAttributeCommitment(ipk, pokSignature, messagesFr[rhIndex].FR, rhIndex, rhAttrCommitmentEnabled(sigType), safeRhNymAuditDataAccess(metadata)) + if err != nil { + return nil, nil, err + } + + /////////////////////// + // Get the challenge // + /////////////////////// + + proofChallenge, Nonce := s.getChallengeHash(pokSignature, Nym, commitNym.Commitment, nymEid, rhNym, msg, sigType) + + //////////////////////// + // Generate responses // + //////////////////////// + + // 1) main + proof := pokSignature.GenerateProof(proofChallenge) + // 2) Nym + proofNym := commitNym.GenerateProof(proofChallenge, []*math.Zr{RNym, sk}) + // 3) NymEid + var proofNymEid *bbs12381g2pub.ProofG1 + if nymEid != nil { + proofNymEid = nymEid.proof.GenerateProof(proofChallenge, []*math.Zr{nymEid.r, messagesFr[eidIndex].FR}) + } + // 4) RhNym + var proofRhNym *bbs12381g2pub.ProofG1 + if rhNym != nil { + proofRhNym = rhNym.proof.GenerateProof(proofChallenge, []*math.Zr{rhNym.r, messagesFr[rhIndex].FR}) + } + + /////////////////// + // Package proof // + /////////////////// + + sigBytes, err := s.packageProof(attributes, Nym, proof, proofNym, nymEid, proofNymEid, rhNym, proofRhNym, cri, Nonce) + if err != nil { + return nil, nil, err + } + + var m *types.IdemixSignerMetadata + if sigType == types.EidNym { + m = &types.IdemixSignerMetadata{ + EidNymAuditData: &types.AttrNymAuditData{ + Nym: nymEid.comm, + Rand: nymEid.r, + Attr: messagesFr[eidIndex].FR, + }, + } + } + + if sigType == types.EidNymRhNym { + m = &types.IdemixSignerMetadata{ + EidNymAuditData: &types.AttrNymAuditData{ + Nym: nymEid.comm, + Rand: nymEid.r, + Attr: messagesFr[eidIndex].FR, + }, + RhNymAuditData: &types.AttrNymAuditData{ + Nym: rhNym.comm, + Rand: rhNym.r, + Attr: messagesFr[rhIndex].FR, + }, + } + } + + return sigBytes, m, nil +} + +// Verify verifies an idemix signature. +func (s *Signer) Verify( + key types.IssuerPublicKey, + signature, msg []byte, + attributes []types.IdemixAttribute, + rhIndex, eidIndex int, + _ *ecdsa.PublicKey, + _ int, + verType types.VerificationType, + meta *types.IdemixSignerMetadata, +) error { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return fmt.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + sig := &Signature{} + err := proto.Unmarshal(signature, sig) + if err != nil { + return fmt.Errorf("proto.Unmarshal error: %w", err) + } + + if sig.NonRevocationProof.RevocationAlg != int32(types.AlgNoRevocation) { + return fmt.Errorf("unsupported revocation algorithm") + } + + if verType == types.ExpectEidNym && + (len(sig.NymEid) == 0 || len(sig.NymEidProof) == 0) { + return fmt.Errorf("no EidNym provided but ExpectEidNym required") + } + + if verType == types.ExpectEidNymRhNym { + if len(sig.NymEid) == 0 || len(sig.NymEidProof) == 0 { + return fmt.Errorf("no EidNym provided but ExpectEidNymRhNym required") + } + if len(sig.NymRh) == 0 || len(sig.NymRhProof) == 0 { + return fmt.Errorf("no RhNym provided but ExpectEidNymRhNym required") + } + } + + if verType == types.ExpectStandard { + if len(sig.NymRh) != 0 || len(sig.NymRhProof) != 0 { + return fmt.Errorf("RhNym available but ExpectStandard required") + } + if len(sig.NymEid) != 0 || len(sig.NymEidProof) != 0 { + return fmt.Errorf("EidNym available but ExpectStandard required") + } + } + + verifyRHNym := (verType == types.BestEffort && sig.NymRh != nil) || verType == types.ExpectEidNymRhNym + verifyEIDNym := (verType == types.BestEffort && sig.NymEid != nil) || verType == types.ExpectEidNym || verType == types.ExpectEidNymRhNym || verifyRHNym + + messages := attributesToSignatureMessage(nil, attributes, s.Curve) + + payload, err := bbs12381g2pub.ParsePoKPayload(sig.MainSignature) + if err != nil { + return fmt.Errorf("parse signature proof: %w", err) + } + + signatureProof, err := bbs12381g2pub.ParseSignatureProof(sig.MainSignature[payload.LenInBytes():]) + if err != nil { + return fmt.Errorf("parse signature proof: %w", err) + } + + if len(payload.Revealed) > len(messages) { + return fmt.Errorf("payload revealed bigger from messages") + } + + revealedMessages := make(map[int]*bbs12381g2pub.SignatureMessage) + for i := range payload.Revealed { + revealedMessages[payload.Revealed[i]] = messages[i] + } + + Nym, err := s.Curve.NewG1FromBytes(sig.Nym) + if err != nil { + return fmt.Errorf("parse nym commit: %w", err) + } + + nymProof, err := bbs12381g2pub.ParseProofG1(sig.NymProof) + if err != nil { + return fmt.Errorf("parse nym proof: %w", err) + } + + var nymEidProof *bbs12381g2pub.ProofG1 + var NymEid *math.G1 + if verifyEIDNym { + nymEidProof, err = bbs12381g2pub.ParseProofG1(sig.NymEidProof) + if err != nil { + return fmt.Errorf("parse nym proof: %w", err) + } + + NymEid, err = s.Curve.NewG1FromBytes(sig.NymEid) + if err != nil { + return fmt.Errorf("parse nym commit: %w", err) + } + } + + var rhNymProof *bbs12381g2pub.ProofG1 + var RhNym *math.G1 + if verifyRHNym { + rhNymProof, err = bbs12381g2pub.ParseProofG1(sig.NymRhProof) + if err != nil { + return fmt.Errorf("parse rh proof: %w", err) + } + + RhNym, err = s.Curve.NewG1FromBytes(sig.NymRh) + if err != nil { + return fmt.Errorf("parse rh commit: %w", err) + } + } + + //////////////////////// + // Hash the challenge // + //////////////////////// + + // hash the signature type first + var challengeBytes []byte + if verifyRHNym { + challengeBytes = []byte(signWithEidNymRhNymLabel) + } else if verifyEIDNym { + challengeBytes = []byte(signWithEidNymLabel) + } else { + challengeBytes = []byte(signLabel) + } + + challengeBytes = append(challengeBytes, signatureProof.GetBytesForChallenge(revealedMessages, ipk.PKwG)...) + + challengeBytes = append(challengeBytes, sig.Nym...) + challengeBytes = append(challengeBytes, nymProof.Commitment.Bytes()...) + + if verifyEIDNym { + challengeBytes = append(challengeBytes, sig.NymEid...) + challengeBytes = append(challengeBytes, nymEidProof.Commitment.Bytes()...) + } + + if verifyRHNym { + challengeBytes = append(challengeBytes, sig.NymRh...) + challengeBytes = append(challengeBytes, rhNymProof.Commitment.Bytes()...) + } + + proofNonce := bbs12381g2pub.ParseProofNonce(msg) + proofNonceBytes := proofNonce.ToBytes() + challengeBytes = append(challengeBytes, proofNonceBytes...) + proofChallenge := bbs12381g2pub.FrFromOKM(challengeBytes) + + challengeBytes = proofChallenge.Bytes() + challengeBytes = append(challengeBytes, sig.Nonce...) + proofChallenge = bbs12381g2pub.FrFromOKM(challengeBytes) + + ////////////////////// + // Verify responses // + ////////////////////// + + // audit eid nym if data provided and verification requested + if (verifyEIDNym || verifyRHNym) && meta != nil { + if meta.EidNymAuditData != nil { + ne := ipk.PKwG.H[eidIndex+1].Mul2( + meta.EidNymAuditData.Attr, + ipk.PKwG.H0, meta.EidNymAuditData.Rand) + + if !ne.Equals(NymEid) { + return fmt.Errorf("signature invalid: nym eid validation failed, does not match regenerated nym eid") + } + + if meta.EidNymAuditData.Nym != nil && !NymEid.Equals(meta.EidNymAuditData.Nym) { + return fmt.Errorf("signature invalid: nym eid validation failed, does not match metadata") + } + } + + if len(meta.EidNym) != 0 { + NymEID_, err := s.Curve.NewG1FromBytes(meta.EidNym) + if err != nil { + return fmt.Errorf("signature invalid: nym eid validation failed, failed to unmarshal meta nym eid") + } + if !NymEID_.Equals(NymEid) { + return fmt.Errorf("signature invalid: nym eid validation failed, signature nym eid does not match metadata") + } + } + } + + // audit rh nym if data provided and verification requested + if verifyRHNym && meta != nil { + if meta.RhNymAuditData != nil { + rn := ipk.PKwG.H[rhIndex+1].Mul2( + meta.RhNymAuditData.Attr, + ipk.PKwG.H0, meta.RhNymAuditData.Rand, + ) + + if !rn.Equals(RhNym) { + return fmt.Errorf("signature invalid: nym rh validation failed, does not match regenerated nym rh") + } + + if meta.RhNymAuditData.Nym != nil && !RhNym.Equals(meta.RhNymAuditData.Nym) { + return fmt.Errorf("signature invalid: nym rh validation failed, does not match metadata") + } + } + + if len(meta.RhNym) != 0 { + RhNym_, err := s.Curve.NewG1FromBytes(meta.RhNym) + if err != nil { + return fmt.Errorf("signature invalid: rh nym validation failed, failed to unmarshal meta rh nym") + } + if !RhNym_.Equals(RhNym) { + return fmt.Errorf("signature invalid: rh nym validation failed, signature rh nym does not match metadata") + } + } + } + + // verify that `sk` in the Nym is the same as the one in the signature + if !nymProof.Responses[AttributeIndexInNym].Equals(signatureProof.ProofVC2.Responses[IndexOffsetVC2Attributes+UserSecretKeyIndex]) { + return fmt.Errorf("failed equality proof for sk") + } + + // verify the proof of knowledge of the Nym + err = nymProof.Verify([]*math.G1{ipk.PKwG.H0, ipk.PKwG.H[UserSecretKeyIndex]}, Nym, proofChallenge) + if err != nil { + return fmt.Errorf("verify nym proof: %w", err) + } + + if verifyEIDNym { + // verify that eid in the NymEid is the same as the one in the signature + if !nymEidProof.Responses[AttributeIndexInNym].Equals(signatureProof.ProofVC2.Responses[sig.NymEidIdx]) { + return fmt.Errorf("failed equality proof for eid") + } + + // verify the proof of knowledge of the Nym + err = nymEidProof.Verify([]*math.G1{ipk.PKwG.H0, ipk.PKwG.H[eidIndex+1]}, NymEid, proofChallenge) + if err != nil { + return fmt.Errorf("verify nym eid proof: %w", err) + } + } + + if verifyRHNym { + // verify that rh in the RhNym is the same as the one in the signature + if !rhNymProof.Responses[AttributeIndexInNym].Equals(signatureProof.ProofVC2.Responses[sig.NymRhIdx]) { + return fmt.Errorf("failed equality proof for rh") + } + + // verify the proof of knowledge of the Rh + err = rhNymProof.Verify([]*math.G1{ipk.PKwG.H0, ipk.PKwG.H[rhIndex+1]}, RhNym, proofChallenge) + if err != nil { + return fmt.Errorf("verify nym eid proof: %w", err) + } + } + + // verify the proof of knowledge of the signature + return signatureProof.Verify(proofChallenge, ipk.PKwG, revealedMessages, messages) +} + +// AuditNymEid permits the auditing of the nym eid generated by a signer +func (s *Signer) AuditNymEid( + key types.IssuerPublicKey, + eidIndex int, + signature []byte, + enrollmentID string, + RNymEid *math.Zr, + verType types.AuditVerificationType, +) error { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return fmt.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + var NymEid *math.G1 + switch verType { + case types.AuditExpectSignature: + sig := &Signature{} + err := proto.Unmarshal(signature, sig) + if err != nil { + return fmt.Errorf("proto.Unmarshal error: %w", err) + } + + NymEid, err = s.Curve.NewG1FromBytes(sig.NymEid) + if err != nil { + return fmt.Errorf("parse nym commit: %w", err) + } + case types.AuditExpectEidNymRhNym: + fallthrough + case types.AuditExpectEidNym: + var err error + NymEid, err = s.Curve.NewG1FromBytes(signature) + if err != nil { + return fmt.Errorf("parse nym commit: %w", err) + } + default: + return fmt.Errorf("invalid audit type [%d]", verType) + } + + eidAttr := bbs12381g2pub.FrFromOKM([]byte(enrollmentID)) + + ne := ipk.PKwG.H[eidIndex+1].Mul2(eidAttr, ipk.PKwG.H0, RNymEid) + + if !ne.Equals(NymEid) { + return fmt.Errorf("eid nym does not match") + } + + return nil +} + +// AuditNymRh permits the auditing of the nym rh generated by a signer +func (s *Signer) AuditNymRh( + key types.IssuerPublicKey, + rhIndex int, + signature []byte, + revocationHandle string, + RNymRh *math.Zr, + verType types.AuditVerificationType, +) error { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return fmt.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + var RhNym *math.G1 + switch verType { + case types.AuditExpectSignature: + sig := &Signature{} + err := proto.Unmarshal(signature, sig) + if err != nil { + return fmt.Errorf("proto.Unmarshal error: %w", err) + } + + RhNym, err = s.Curve.NewG1FromBytes(sig.NymRh) + if err != nil { + return fmt.Errorf("parse rh commit: %w", err) + } + case types.AuditExpectEidNymRhNym: + var err error + RhNym, err = s.Curve.NewG1FromBytes(signature) + if err != nil { + return fmt.Errorf("parse nym commit: %w", err) + } + default: + return fmt.Errorf("invalid audit type [%d]", verType) + } + + rhAttr := bbs12381g2pub.FrFromOKM([]byte(revocationHandle)) + + nr := ipk.PKwG.H[rhIndex+1].Mul2(rhAttr, ipk.PKwG.H0, RNymRh) + + if !nr.Equals(RhNym) { + return fmt.Errorf("rh nym does not match") + } + + return nil +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/user.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/user.go new file mode 100644 index 00000000000..4dbc62381ee --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/user.go @@ -0,0 +1,85 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package aries + +import ( + "io" + + "github.com/IBM/idemix/bccsp/types" + math "github.com/IBM/mathlib" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" + "github.com/pkg/errors" +) + +type User struct { + Curve *math.Curve + Rng io.Reader +} + +// NewKey generates a new User secret key +func (u *User) NewKey() (*math.Zr, error) { + r := u.Curve.NewRandomZr(u.Rng) + + return r, nil +} + +// NewKeyFromBytes converts the passed bytes to a User secret key +func (u *User) NewKeyFromBytes(raw []byte) (*math.Zr, error) { + if len(raw) != u.Curve.ScalarByteSize { + return nil, errors.Errorf("invalid length, expected [%d], got [%d]", u.Curve.ScalarByteSize, len(raw)) + } + + return u.Curve.NewZrFromBytes(raw), nil +} + +// MakeNym creates a new unlinkable pseudonym +func (u *User) MakeNym(sk *math.Zr, key types.IssuerPublicKey) (*math.G1, *math.Zr, error) { + ipk, ok := key.(*IssuerPublicKey) + if !ok { + return nil, nil, errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + // Construct a commitment to the sk + // Nym = h_0^r \cdot h_1^sk + + rNym := u.Curve.NewRandomZr(u.Rng) + + cb := bbs12381g2pub.NewCommitmentBuilder(2) + cb.Add(ipk.PKwG.H0, rNym) + cb.Add(ipk.PKwG.H[UserSecretKeyIndex], sk) + nym := cb.Build() + + return nym, rNym, nil +} + +func (u *User) NewNymFromBytes(raw []byte) (*math.G1, *math.Zr, error) { + if len(raw) != u.Curve.ScalarByteSize+u.Curve.G1ByteSize { + return nil, nil, errors.Errorf("invalid length, expected [%d], got [%d]", u.Curve.ScalarByteSize+u.Curve.G1ByteSize, len(raw)) + } + + rnd := u.Curve.NewZrFromBytes(raw[:u.Curve.ScalarByteSize]) + nym, err := u.Curve.NewG1FromBytes(raw[u.Curve.ScalarByteSize:]) + if err != nil { + return nil, nil, err + } + + return nym, rnd, err +} + +// NewPublicNymFromBytes converts the passed bytes to a public nym +func (u *User) NewPublicNymFromBytes(raw []byte) (*math.G1, error) { + if len(raw) != u.Curve.G1ByteSize { + return nil, errors.Errorf("invalid length, expected [%d], got [%d]", u.Curve.G1ByteSize, len(raw)) + } + + nym, err := u.Curve.NewG1FromBytes(raw) + if err != nil { + return nil, err + } + + return nym, err +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/aries/util.go b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/util.go new file mode 100644 index 00000000000..9021617afe3 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/aries/util.go @@ -0,0 +1,81 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package aries + +import ( + "github.com/IBM/idemix/bccsp/types" + math "github.com/IBM/mathlib" + "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub" +) + +func attributesToSignatureMessage(sk *math.Zr, attributes []types.IdemixAttribute, curve *math.Curve) []*bbs12381g2pub.SignatureMessage { + var msgsZr []*bbs12381g2pub.SignatureMessage + + if sk == nil { + msgsZr = make([]*bbs12381g2pub.SignatureMessage, 0, len(attributes)) + } else { + msgsZr = make([]*bbs12381g2pub.SignatureMessage, 1, len(attributes)+1) + msgsZr[UserSecretKeyIndex] = &bbs12381g2pub.SignatureMessage{ + FR: sk, + Idx: UserSecretKeyIndex, + } + } + + for i, msg := range attributes { + switch msg.Type { + case types.IdemixBytesAttribute: + msgsZr = append(msgsZr, &bbs12381g2pub.SignatureMessage{ + FR: bbs12381g2pub.FrFromOKM(msg.Value.([]byte)), + Idx: i + 1, + }) + case types.IdemixIntAttribute: + msgsZr = append(msgsZr, &bbs12381g2pub.SignatureMessage{ + FR: curve.NewZrFromInt(int64(msg.Value.(int))), + Idx: i + 1, + }) + case types.IdemixHiddenAttribute: + continue + } + } + + return msgsZr +} + +func revealedAttributesIndex(attributes []types.IdemixAttribute) []int { + revealed := make([]int, 0, len(attributes)) + + for i, msg := range attributes { + if msg.Type != types.IdemixHiddenAttribute { + revealed = append(revealed, i+1) + } + } + + return revealed +} + +func (c *Credential) toSignatureMessage(sk *math.Zr, curve *math.Curve) []*bbs12381g2pub.SignatureMessage { + var msgsZr []*bbs12381g2pub.SignatureMessage + + if sk == nil { + msgsZr = make([]*bbs12381g2pub.SignatureMessage, 0, len(c.Attrs)) + } else { + msgsZr = make([]*bbs12381g2pub.SignatureMessage, 1, len(c.Attrs)+1) + msgsZr[UserSecretKeyIndex] = &bbs12381g2pub.SignatureMessage{ + FR: sk, + Idx: UserSecretKeyIndex, + } + } + + for i, msg := range c.Attrs { + msgsZr = append(msgsZr, &bbs12381g2pub.SignatureMessage{ + FR: curve.NewZrFromBytes(msg), + Idx: i + 1, + }) + } + + return msgsZr +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credential.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credential.go index 38f97eaa6e2..062a1486cd9 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credential.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credential.go @@ -8,9 +8,8 @@ package bridge import ( "bytes" - bccsp "github.com/IBM/idemix/bccsp/schemes" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/golang/protobuf/proto" "github.com/pkg/errors" @@ -28,7 +27,7 @@ type Credential struct { // a serialised credential request, and a list of attribute values. // Notice that attributes should not contain attributes whose type is IdemixHiddenAttribute // cause the credential needs to carry all the attribute values. -func (c *Credential) Sign(key handlers.IssuerSecretKey, credentialRequest []byte, attributes []bccsp.IdemixAttribute) (res []byte, err error) { +func (c *Credential) Sign(key types.IssuerSecretKey, credentialRequest []byte, attributes []types.IdemixAttribute) (res []byte, err error) { defer func() { if r := recover(); r != nil { res = nil @@ -50,9 +49,9 @@ func (c *Credential) Sign(key handlers.IssuerSecretKey, credentialRequest []byte attrValues := make([]*math.Zr, len(attributes)) for i := 0; i < len(attributes); i++ { switch attributes[i].Type { - case bccsp.IdemixBytesAttribute: + case types.IdemixBytesAttribute: attrValues[i] = c.Idemix.Curve.HashToZr(attributes[i].Value.([]byte)) - case bccsp.IdemixIntAttribute: + case types.IdemixIntAttribute: var value int64 if v, ok := attributes[i].Value.(int); ok { value = int64(v) @@ -79,7 +78,7 @@ func (c *Credential) Sign(key handlers.IssuerSecretKey, credentialRequest []byte // in input the user secret key (sk), the issuer public key (ipk), the serialised credential (credential), // and a list of attributes. The list of attributes is optional, in case it is specified, Verify // checks that the credential carries the specified attributes. -func (c *Credential) Verify(sk *math.Zr, ipk handlers.IssuerPublicKey, credential []byte, attributes []bccsp.IdemixAttribute) (err error) { +func (c *Credential) Verify(sk *math.Zr, ipk types.IssuerPublicKey, credential []byte, attributes []types.IdemixAttribute) (err error) { defer func() { if r := recover(); r != nil { err = errors.Errorf("failure [%s]", r) @@ -99,13 +98,13 @@ func (c *Credential) Verify(sk *math.Zr, ipk handlers.IssuerPublicKey, credentia for i := 0; i < len(attributes); i++ { switch attributes[i].Type { - case bccsp.IdemixBytesAttribute: + case types.IdemixBytesAttribute: if !bytes.Equal( c.Idemix.Curve.HashToZr(attributes[i].Value.([]byte)).Bytes(), cred.Attrs[i]) { return errors.Errorf("credential does not contain the correct attribute value at position [%d]", i) } - case bccsp.IdemixIntAttribute: + case types.IdemixIntAttribute: var value int64 if v, ok := attributes[i].Value.(int); ok { value = int64(v) @@ -120,7 +119,7 @@ func (c *Credential) Verify(sk *math.Zr, ipk handlers.IssuerPublicKey, credentia cred.Attrs[i]) { return errors.Errorf("credential does not contain the correct attribute value at position [%d]", i) } - case bccsp.IdemixHiddenAttribute: + case types.IdemixHiddenAttribute: continue default: return errors.Errorf("attribute type not allowed or supported [%v] at position [%d]", attributes[i].Type, i) diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credrequest.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credrequest.go index a7d8d07804f..8cde1593f83 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credrequest.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/credrequest.go @@ -9,7 +9,7 @@ import ( "bytes" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/golang/protobuf/proto" "github.com/pkg/errors" @@ -25,7 +25,7 @@ type CredRequest struct { // Sign produces an idemix credential request. It takes in input a user secret key and // an issuer public key. -func (cr *CredRequest) Sign(sk *math.Zr, ipk handlers.IssuerPublicKey, nonce []byte) (res []byte, err error) { +func (cr *CredRequest) Sign(sk *math.Zr, ipk types.IssuerPublicKey, nonce []byte) (res []byte, err error) { defer func() { if r := recover(); r != nil { res = nil @@ -37,8 +37,8 @@ func (cr *CredRequest) Sign(sk *math.Zr, ipk handlers.IssuerPublicKey, nonce []b if !ok { return nil, errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) } - if len(nonce) != cr.Idemix.Curve.FieldBytes { - return nil, errors.Errorf("invalid issuer nonce, expected length %d, got %d", cr.Idemix.Curve.FieldBytes, len(nonce)) + if len(nonce) != cr.Idemix.Curve.ScalarByteSize { + return nil, errors.Errorf("invalid issuer nonce, expected length %d, got %d", cr.Idemix.Curve.ScalarByteSize, len(nonce)) } credRequest, err := cr.Idemix.NewCredRequest( @@ -57,7 +57,7 @@ func (cr *CredRequest) Sign(sk *math.Zr, ipk handlers.IssuerPublicKey, nonce []b // Verify checks that the passed credential request is valid with the respect to the passed // issuer public key. -func (cr *CredRequest) Verify(credentialRequest []byte, ipk handlers.IssuerPublicKey, nonce []byte) (err error) { +func (cr *CredRequest) Verify(credentialRequest []byte, ipk types.IssuerPublicKey, nonce []byte) (err error) { defer func() { if r := recover(); r != nil { err = errors.Errorf("failure [%s]", r) @@ -81,8 +81,8 @@ func (cr *CredRequest) Verify(credentialRequest []byte, ipk handlers.IssuerPubli } // Nonce checks - if len(nonce) != cr.Idemix.Curve.FieldBytes { - return errors.Errorf("invalid issuer nonce, expected length %d, got %d", cr.Idemix.Curve.FieldBytes, len(nonce)) + if len(nonce) != cr.Idemix.Curve.ScalarByteSize { + return errors.Errorf("invalid issuer nonce, expected length %d, got %d", cr.Idemix.Curve.ScalarByteSize, len(nonce)) } if !bytes.Equal(nonce, credRequest.IssuerNonce) { return errors.Errorf("invalid nonce, expected [%v], got [%v]", nonce, credRequest.IssuerNonce) diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/issuer.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/issuer.go index 1c98a955792..ae88e727032 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/issuer.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/issuer.go @@ -8,9 +8,9 @@ package bridge import ( "fmt" - bccsp "github.com/IBM/idemix/bccsp/schemes" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" "github.com/golang/protobuf/proto" "github.com/pkg/errors" ) @@ -37,7 +37,7 @@ func (o *IssuerSecretKey) Bytes() ([]byte, error) { return proto.Marshal(o.SK) } -func (o *IssuerSecretKey) Public() handlers.IssuerPublicKey { +func (o *IssuerSecretKey) Public() types.IssuerPublicKey { return &IssuerPublicKey{o.SK.Ipk} } @@ -48,7 +48,7 @@ type Issuer struct { } // NewKey generates a new issuer key-pair -func (i *Issuer) NewKey(attributeNames []string) (res handlers.IssuerSecretKey, err error) { +func (i *Issuer) NewKey(attributeNames []string) (res types.IssuerSecretKey, err error) { defer func() { if r := recover(); r != nil { res = nil @@ -66,7 +66,7 @@ func (i *Issuer) NewKey(attributeNames []string) (res handlers.IssuerSecretKey, return } -func (i *Issuer) NewKeyFromBytes(raw []byte, attributes []string) (res handlers.IssuerSecretKey, err error) { +func (i *Issuer) NewKeyFromBytes(raw []byte, attributes []string) (res types.IssuerSecretKey, err error) { defer func() { if r := recover(); r != nil { res = nil @@ -84,7 +84,7 @@ func (i *Issuer) NewKeyFromBytes(raw []byte, attributes []string) (res handlers. return } -func (i *Issuer) NewPublicKeyFromBytes(raw []byte, attributes []string) (res handlers.IssuerPublicKey, err error) { +func (i *Issuer) NewPublicKeyFromBytes(raw []byte, attributes []string) (res types.IssuerPublicKey, err error) { defer func() { if r := recover(); r != nil { res = nil diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/nymsignaturescheme.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/nymsignaturescheme.go index 442668dbdca..c101b31029e 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/nymsignaturescheme.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/nymsignaturescheme.go @@ -7,7 +7,7 @@ package bridge import ( idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/golang/protobuf/proto" @@ -23,7 +23,7 @@ type NymSignatureScheme struct { // Sign produces a signature over the passed digest. It takes in input, the user secret key (sk), // the pseudonym public key (Nym) and secret key (RNym), and the issuer public key (ipk). -func (n *NymSignatureScheme) Sign(sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk handlers.IssuerPublicKey, digest []byte) (res []byte, err error) { +func (n *NymSignatureScheme) Sign(sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk types.IssuerPublicKey, digest []byte) (res []byte, err error) { defer func() { if r := recover(); r != nil { res = nil @@ -53,7 +53,7 @@ func (n *NymSignatureScheme) Sign(sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk // Verify checks that the passed signatures is valid with the respect to the passed digest, issuer public key, // and pseudonym public key. -func (n *NymSignatureScheme) Verify(ipk handlers.IssuerPublicKey, Nym *math.G1, signature, digest []byte) (err error) { +func (n *NymSignatureScheme) Verify(ipk types.IssuerPublicKey, Nym *math.G1, signature, digest []byte) (err error) { defer func() { if r := recover(); r != nil { err = errors.Errorf("failure [%s]", r) diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/revocation.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/revocation.go index b82d25d4f98..47be5ca2b01 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/revocation.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/revocation.go @@ -8,8 +8,8 @@ package bridge import ( "crypto/ecdsa" - bccsp "github.com/IBM/idemix/bccsp/schemes" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" + bccsp "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/golang/protobuf/proto" "github.com/pkg/errors" diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/signaturescheme.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/signaturescheme.go index 35a148e166e..f50b92c6c94 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/signaturescheme.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/signaturescheme.go @@ -3,14 +3,15 @@ Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ + package bridge import ( "crypto/ecdsa" - bccsp "github.com/IBM/idemix/bccsp/schemes" idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + "github.com/IBM/idemix/bccsp/types" + bccsp "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/golang/protobuf/proto" "github.com/pkg/errors" @@ -25,8 +26,8 @@ type SignatureScheme struct { // Sign produces an idemix-signature with the respect to the passed serialised credential (cred), // user secret key (sk), pseudonym public key (Nym) and secret key (RNym), issuer public key (ipk), // and attributes to be disclosed. -func (s *SignatureScheme) Sign(cred []byte, sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk handlers.IssuerPublicKey, attributes []bccsp.IdemixAttribute, - msg []byte, rhIndex, eidIndex int, criRaw []byte, sigType bccsp.SignatureType) (res []byte, meta *bccsp.IdemixSignerMetadata, err error) { +func (s *SignatureScheme) Sign(cred []byte, sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk types.IssuerPublicKey, attributes []bccsp.IdemixAttribute, + msg []byte, rhIndex, eidIndex int, criRaw []byte, sigType bccsp.SignatureType, metadata *bccsp.IdemixSignerMetadata) (res []byte, meta *bccsp.IdemixSignerMetadata, err error) { defer func() { if r := recover(); r != nil { res = nil @@ -68,11 +69,14 @@ func (s *SignatureScheme) Sign(cred []byte, sk *math.Zr, Nym *math.G1, RNym *mat iipk.PK, disclosure, msg, - rhIndex, eidIndex, + rhIndex, + eidIndex, cri, newRandOrPanic(s.Idemix.Curve), s.Translator, - sigType) + sigType, + metadata, + ) if err != nil { return nil, nil, errors.WithMessage(err, "failed creating new signature") } @@ -85,12 +89,14 @@ func (s *SignatureScheme) Sign(cred []byte, sk *math.Zr, Nym *math.G1, RNym *mat return sigBytes, meta, nil } +// AuditNymEid Audits the pseudonymous enrollment id of a signature func (s *SignatureScheme) AuditNymEid( - ipk handlers.IssuerPublicKey, + ipk types.IssuerPublicKey, eidIndex int, signature []byte, enrollmentID string, RNymEid *math.Zr, + verType bccsp.AuditVerificationType, ) (err error) { defer func() { if r := recover(); r != nil { @@ -103,28 +109,100 @@ func (s *SignatureScheme) AuditNymEid( return errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) } - sig := &idemix.Signature{} - err = proto.Unmarshal(signature, sig) - if err != nil { - return err + eidAttr := s.Idemix.Curve.HashToZr([]byte(enrollmentID)) + + switch verType { + case bccsp.AuditExpectSignature: + sig := &idemix.Signature{} + err = proto.Unmarshal(signature, sig) + if err != nil { + return err + } + return sig.AuditNymEid( + iipk.PK, + eidAttr, + eidIndex, + RNymEid, + s.Idemix.Curve, + s.Translator, + ) + case bccsp.AuditExpectEidNymRhNym: + fallthrough + case bccsp.AuditExpectEidNym: + // 1. cast signature to NymEID + nymEID := idemix.NymEID(signature) + // 2. check audit on nymEID + return nymEID.AuditNymEid( + iipk.PK, + eidAttr, + eidIndex, + RNymEid, + s.Idemix.Curve, + s.Translator, + ) + default: + return errors.Errorf("invalid audit type [%d]", verType) } +} - eidAttr := s.Idemix.Curve.HashToZr([]byte(enrollmentID)) +// AuditNymRh Audits the pseudonymous revocation handle of a signature +func (s *SignatureScheme) AuditNymRh( + ipk types.IssuerPublicKey, + rhIndex int, + signature []byte, + revocationHandle string, + RNymRh *math.Zr, + verType bccsp.AuditVerificationType, +) (err error) { + defer func() { + if r := recover(); r != nil { + err = errors.Errorf("failure [%s]", r) + } + }() - return sig.AuditNymEid( - iipk.PK, - eidAttr, - eidIndex, - RNymEid, - s.Idemix.Curve, - s.Translator, - ) + iipk, ok := ipk.(*IssuerPublicKey) + if !ok { + return errors.Errorf("invalid issuer public key, expected *IssuerPublicKey, got [%T]", ipk) + } + + rhAttr := s.Idemix.Curve.HashToZr([]byte(revocationHandle)) + + switch verType { + case bccsp.AuditExpectSignature: + sig := &idemix.Signature{} + err = proto.Unmarshal(signature, sig) + if err != nil { + return err + } + return sig.AuditNymRh( + iipk.PK, + rhAttr, + rhIndex, + RNymRh, + s.Idemix.Curve, + s.Translator, + ) + case bccsp.AuditExpectEidNymRhNym: + // 1. cast signature to NymRH + nymRH := idemix.NymRH(signature) + // 2. check audit on nymRH + return nymRH.AuditNymRh( + iipk.PK, + rhAttr, + rhIndex, + RNymRh, + s.Idemix.Curve, + s.Translator, + ) + default: + return errors.Errorf("invalid audit type [%d]", verType) + } } // Verify checks that an idemix signature is valid with the respect to the passed issuer public key, digest, attributes, // revocation index (rhIndex), revocation public key, and epoch. func (s *SignatureScheme) Verify( - ipk handlers.IssuerPublicKey, + ipk types.IssuerPublicKey, signature, digest []byte, attributes []bccsp.IdemixAttribute, rhIndex, eidIndex int, @@ -149,7 +227,6 @@ func (s *SignatureScheme) Verify( if err != nil { return err } - disclosure := make([]byte, len(attributes)) attrValues := make([]*math.Zr, len(attributes)) for i := 0; i < len(attributes); i++ { diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/user.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/user.go index be3f2a38d37..bdaf205226f 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/user.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/bridge/user.go @@ -7,7 +7,7 @@ package bridge import ( idemix "github.com/IBM/idemix/bccsp/schemes/dlog/crypto" - "github.com/IBM/idemix/bccsp/schemes/dlog/handlers" + "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/pkg/errors" ) @@ -33,8 +33,8 @@ func (u *User) NewKey() (res *math.Zr, err error) { } func (u *User) NewKeyFromBytes(raw []byte) (res *math.Zr, err error) { - if len(raw) != u.Idemix.Curve.FieldBytes { - return nil, errors.Errorf("invalid length, expected [%d], got [%d]", u.Idemix.Curve.FieldBytes, len(raw)) + if len(raw) != u.Idemix.Curve.ScalarByteSize { + return nil, errors.Errorf("invalid length, expected [%d], got [%d]", u.Idemix.Curve.ScalarByteSize, len(raw)) } res = u.Idemix.Curve.NewZrFromBytes(raw) @@ -43,7 +43,7 @@ func (u *User) NewKeyFromBytes(raw []byte) (res *math.Zr, err error) { } // MakeNym generates a new pseudonym key-pair derived from the passed user secret key (sk) and issuer public key (ipk) -func (u *User) MakeNym(sk *math.Zr, ipk handlers.IssuerPublicKey) (r1 *math.G1, r2 *math.Zr, err error) { +func (u *User) MakeNym(sk *math.Zr, ipk types.IssuerPublicKey) (r1 *math.G1, r2 *math.Zr, err error) { defer func() { if r := recover(); r != nil { r1 = nil diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/credrequest.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/credrequest.go index 28592a4408a..7f5b8eb0b1f 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/credrequest.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/credrequest.go @@ -59,7 +59,7 @@ func newCredRequest(sk *math.Zr, IssuerNonce []byte, ipk *IssuerPublicKey, rng i // 3 elements of G1 each taking 2*math.FieldBytes+1 bytes // hash of the issuer public key of length math.FieldBytes // issuer nonce of length math.FieldBytes - proofData := make([]byte, len([]byte(credRequestLabel))+3*(2*curve.FieldBytes+1)+2*curve.FieldBytes) + proofData := make([]byte, len([]byte(credRequestLabel))+3*curve.G1ByteSize+2*curve.ScalarByteSize) index := 0 index = appendBytesString(proofData, index, credRequestLabel) index = appendBytesG1(proofData, index, t) @@ -108,7 +108,7 @@ func (m *CredRequest) Check(ipk *IssuerPublicKey, curve *math.Curve, tr Translat t.Sub(Nym.Mul(ProofC)) // t = h_{sk}^s / Nym^C // Recompute challenge - proofData := make([]byte, len([]byte(credRequestLabel))+3*(2*curve.FieldBytes+1)+2*curve.FieldBytes) + proofData := make([]byte, len([]byte(credRequestLabel))+3*curve.G1ByteSize+2*curve.ScalarByteSize) index := 0 index = appendBytesString(proofData, index, credRequestLabel) index = appendBytesG1(proofData, index, t) diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.pb.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.pb.go index bb801ce9d84..b02cedd71b9 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.pb.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.pb.go @@ -329,6 +329,9 @@ func (m *CredRequest) GetProofS() []byte { return nil } +// EIDNym specifies a pseudonymous enrollment id object that consists of +// nym - pseudonymous enrollment id +// s_eid - field element type EIDNym struct { Nym *amcl.ECP `protobuf:"bytes,1,opt,name=nym,proto3" json:"nym,omitempty"` ProofSEid []byte `protobuf:"bytes,2,opt,name=proof_s_eid,json=proofSEid,proto3" json:"proof_s_eid,omitempty"` @@ -376,6 +379,56 @@ func (m *EIDNym) GetProofSEid() []byte { return nil } +// RHNym specifies a pseudonymous revocation handle object that consists of +// nym - pseudonymous revocation handle +// s_rh - field element +type RHNym struct { + Nym *amcl.ECP `protobuf:"bytes,1,opt,name=nym,proto3" json:"nym,omitempty"` + ProofSRh []byte `protobuf:"bytes,2,opt,name=proof_s_rh,json=proofSRh,proto3" json:"proof_s_rh,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RHNym) Reset() { *m = RHNym{} } +func (m *RHNym) String() string { return proto.CompactTextString(m) } +func (*RHNym) ProtoMessage() {} +func (*RHNym) Descriptor() ([]byte, []int) { + return fileDescriptor_7f94c3d451691341, []int{5} +} + +func (m *RHNym) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_RHNym.Unmarshal(m, b) +} +func (m *RHNym) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_RHNym.Marshal(b, m, deterministic) +} +func (m *RHNym) XXX_Merge(src proto.Message) { + xxx_messageInfo_RHNym.Merge(m, src) +} +func (m *RHNym) XXX_Size() int { + return xxx_messageInfo_RHNym.Size(m) +} +func (m *RHNym) XXX_DiscardUnknown() { + xxx_messageInfo_RHNym.DiscardUnknown(m) +} + +var xxx_messageInfo_RHNym proto.InternalMessageInfo + +func (m *RHNym) GetNym() *amcl.ECP { + if m != nil { + return m.Nym + } + return nil +} + +func (m *RHNym) GetProofSRh() []byte { + if m != nil { + return m.ProofSRh + } + return nil +} + // Signature specifies a signature object that consists of // a_prime, a_bar, b_prime, proof_* - randomized credential signature values // and a zero-knowledge proof of knowledge of a credential @@ -401,6 +454,7 @@ type Signature struct { Epoch int64 `protobuf:"varint,16,opt,name=epoch,proto3" json:"epoch,omitempty"` NonRevocationProof *NonRevocationProof `protobuf:"bytes,17,opt,name=non_revocation_proof,json=nonRevocationProof,proto3" json:"non_revocation_proof,omitempty"` EidNym *EIDNym `protobuf:"bytes,18,opt,name=eid_nym,json=eidNym,proto3" json:"eid_nym,omitempty"` + RhNym *RHNym `protobuf:"bytes,19,opt,name=rh_nym,json=rhNym,proto3" json:"rh_nym,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -410,7 +464,7 @@ func (m *Signature) Reset() { *m = Signature{} } func (m *Signature) String() string { return proto.CompactTextString(m) } func (*Signature) ProtoMessage() {} func (*Signature) Descriptor() ([]byte, []int) { - return fileDescriptor_7f94c3d451691341, []int{5} + return fileDescriptor_7f94c3d451691341, []int{6} } func (m *Signature) XXX_Unmarshal(b []byte) error { @@ -557,6 +611,13 @@ func (m *Signature) GetEidNym() *EIDNym { return nil } +func (m *Signature) GetRhNym() *RHNym { + if m != nil { + return m.RhNym + } + return nil +} + // NonRevocationProof contains proof that the credential is not revoked type NonRevocationProof struct { RevocationAlg int32 `protobuf:"varint,1,opt,name=revocation_alg,json=revocationAlg,proto3" json:"revocation_alg,omitempty"` @@ -570,7 +631,7 @@ func (m *NonRevocationProof) Reset() { *m = NonRevocationProof{} } func (m *NonRevocationProof) String() string { return proto.CompactTextString(m) } func (*NonRevocationProof) ProtoMessage() {} func (*NonRevocationProof) Descriptor() ([]byte, []int) { - return fileDescriptor_7f94c3d451691341, []int{6} + return fileDescriptor_7f94c3d451691341, []int{7} } func (m *NonRevocationProof) XXX_Unmarshal(b []byte) error { @@ -615,7 +676,7 @@ type NymSignature struct { ProofC []byte `protobuf:"bytes,1,opt,name=proof_c,json=proofC,proto3" json:"proof_c,omitempty"` // proof_s_sk is the s-value proving knowledge of the user secret key ProofSSk []byte `protobuf:"bytes,2,opt,name=proof_s_sk,json=proofSSk,proto3" json:"proof_s_sk,omitempty"` - //proof_s_r_nym is the s-value proving knowledge of the pseudonym secret + // proof_s_r_nym is the s-value proving knowledge of the pseudonym secret ProofSRNym []byte `protobuf:"bytes,3,opt,name=proof_s_r_nym,json=proofSRNym,proto3" json:"proof_s_r_nym,omitempty"` // nonce is a fresh nonce used for the signature Nonce []byte `protobuf:"bytes,4,opt,name=nonce,proto3" json:"nonce,omitempty"` @@ -628,7 +689,7 @@ func (m *NymSignature) Reset() { *m = NymSignature{} } func (m *NymSignature) String() string { return proto.CompactTextString(m) } func (*NymSignature) ProtoMessage() {} func (*NymSignature) Descriptor() ([]byte, []int) { - return fileDescriptor_7f94c3d451691341, []int{7} + return fileDescriptor_7f94c3d451691341, []int{8} } func (m *NymSignature) XXX_Unmarshal(b []byte) error { @@ -697,7 +758,7 @@ func (m *CredentialRevocationInformation) Reset() { *m = CredentialRevoc func (m *CredentialRevocationInformation) String() string { return proto.CompactTextString(m) } func (*CredentialRevocationInformation) ProtoMessage() {} func (*CredentialRevocationInformation) Descriptor() ([]byte, []int) { - return fileDescriptor_7f94c3d451691341, []int{8} + return fileDescriptor_7f94c3d451691341, []int{9} } func (m *CredentialRevocationInformation) XXX_Unmarshal(b []byte) error { @@ -759,6 +820,7 @@ func init() { proto.RegisterType((*Credential)(nil), "idemix.Credential") proto.RegisterType((*CredRequest)(nil), "idemix.CredRequest") proto.RegisterType((*EIDNym)(nil), "idemix.EIDNym") + proto.RegisterType((*RHNym)(nil), "idemix.RHNym") proto.RegisterType((*Signature)(nil), "idemix.Signature") proto.RegisterType((*NonRevocationProof)(nil), "idemix.NonRevocationProof") proto.RegisterType((*NymSignature)(nil), "idemix.NymSignature") @@ -770,59 +832,65 @@ func init() { } var fileDescriptor_7f94c3d451691341 = []byte{ - // 860 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x55, 0xcd, 0x6e, 0xe3, 0x36, - 0x10, 0x86, 0x22, 0x5b, 0x8e, 0xc7, 0x4a, 0xbc, 0xcb, 0x06, 0x88, 0x90, 0x2e, 0xb6, 0xae, 0x80, - 0x34, 0x6e, 0x0f, 0x71, 0xe3, 0xf4, 0xd4, 0xdb, 0x26, 0x6b, 0xb4, 0x41, 0x5b, 0xc3, 0xa0, 0x6f, - 0xbd, 0x10, 0x94, 0xc4, 0xb5, 0x08, 0x59, 0x3f, 0x25, 0xe5, 0x6e, 0x7d, 0x69, 0x5f, 0xa3, 0xcf, - 0xd3, 0x27, 0xe8, 0x23, 0x2d, 0x48, 0xca, 0x92, 0x12, 0x25, 0x7b, 0x31, 0xc4, 0x99, 0xe1, 0x37, - 0x1f, 0xbf, 0xf9, 0x68, 0xc2, 0x37, 0x41, 0x18, 0xca, 0x62, 0x26, 0xc3, 0x98, 0xa5, 0x4c, 0xce, - 0xa2, 0x6d, 0xbe, 0x99, 0x85, 0x62, 0x5f, 0x94, 0xf9, 0x8c, 0x47, 0x2c, 0xe5, 0x7f, 0x5d, 0x17, - 0x22, 0x2f, 0x73, 0xe4, 0x98, 0xd5, 0xc5, 0x0f, 0x2f, 0xd7, 0x97, 0x82, 0x66, 0x72, 0x4b, 0xcb, - 0x5c, 0xcc, 0x68, 0x1a, 0x6e, 0xf5, 0x8f, 0xd9, 0xed, 0xff, 0x77, 0x04, 0xe3, 0x07, 0x29, 0x77, - 0x4c, 0xac, 0x76, 0xc1, 0x96, 0x87, 0xbf, 0xb0, 0x3d, 0xba, 0x82, 0x31, 0x2d, 0x4b, 0xc1, 0x83, - 0x5d, 0xc9, 0x48, 0x46, 0x53, 0x26, 0x3d, 0x6b, 0x62, 0x4f, 0x87, 0xf8, 0xb4, 0x0e, 0x2f, 0x55, - 0x14, 0xbd, 0x81, 0x5e, 0x4c, 0x64, 0xe2, 0x1d, 0x4d, 0xac, 0xe9, 0x68, 0x3e, 0xbc, 0xd6, 0xb8, - 0x8b, 0xfb, 0x15, 0xb6, 0xe3, 0x75, 0x82, 0x26, 0xe0, 0xc4, 0x44, 0xd0, 0x2c, 0xf2, 0xec, 0xa7, - 0xf9, 0x7e, 0x8c, 0x69, 0x16, 0x21, 0x1f, 0x06, 0x31, 0x51, 0x98, 0xd2, 0xeb, 0x4d, 0xec, 0xc7, - 0x25, 0x4e, 0xfc, 0x4e, 0x25, 0x90, 0x07, 0xd6, 0x47, 0xaf, 0xaf, 0x01, 0xa0, 0xce, 0xce, 0xb1, - 0xf5, 0x51, 0xe1, 0x07, 0x54, 0x90, 0xcd, 0x8d, 0xe7, 0x74, 0xf0, 0x03, 0x2a, 0x7e, 0xba, 0xa9, - 0x2b, 0xe6, 0xde, 0xe0, 0xd9, 0x8a, 0x39, 0x3a, 0x87, 0x41, 0x21, 0xf2, 0xfc, 0x03, 0x09, 0xbd, - 0xe3, 0x89, 0x35, 0x75, 0xb1, 0xa3, 0x97, 0xf7, 0x4d, 0x42, 0x7a, 0xc3, 0x56, 0x62, 0x8d, 0x10, - 0xf4, 0x62, 0x2a, 0x63, 0x0f, 0x74, 0x54, 0x7f, 0xfb, 0x3f, 0xc3, 0xd0, 0x68, 0xa8, 0xd4, 0x7b, - 0x05, 0x36, 0x97, 0x89, 0x67, 0xe9, 0xbc, 0xfa, 0x44, 0xdf, 0x82, 0xcd, 0x8b, 0x83, 0x4a, 0xe7, - 0xd7, 0xd5, 0xf4, 0x9e, 0xa8, 0x8e, 0x55, 0x8d, 0x5f, 0x00, 0xdc, 0x0b, 0x16, 0xb1, 0xac, 0xe4, - 0x74, 0x8b, 0xce, 0xc1, 0xa2, 0x1a, 0xe8, 0x11, 0x75, 0x8b, 0xaa, 0x44, 0xd0, 0x55, 0xdd, 0x0a, - 0x90, 0x0b, 0x16, 0xd3, 0x72, 0xbb, 0xd8, 0x62, 0x6a, 0xa5, 0x94, 0xd5, 0x2b, 0x89, 0xce, 0xa0, - 0x6f, 0xb4, 0xee, 0x4f, 0xec, 0xa9, 0x8b, 0xcd, 0xc2, 0xff, 0x07, 0x46, 0xaa, 0x23, 0x66, 0x7f, - 0xec, 0x98, 0x2c, 0xd1, 0x97, 0x60, 0x67, 0xfb, 0xb4, 0xdb, 0x54, 0x45, 0xd1, 0xd7, 0xe0, 0x72, - 0xcd, 0x9a, 0x64, 0x79, 0x16, 0x32, 0xcd, 0xc0, 0xc5, 0x23, 0x13, 0x5b, 0xaa, 0x50, 0x5b, 0x50, - 0xfb, 0x25, 0x41, 0x7b, 0x6d, 0x41, 0xfd, 0x05, 0x38, 0x8b, 0x87, 0xf7, 0xcb, 0x7d, 0xfa, 0xf9, - 0xde, 0x6f, 0x61, 0x54, 0xed, 0x27, 0x8c, 0x47, 0x55, 0xeb, 0xa1, 0xc1, 0x58, 0xf0, 0xc8, 0xff, - 0xb7, 0x0f, 0xc3, 0x35, 0xdf, 0x64, 0xb4, 0xdc, 0x09, 0xa6, 0x9c, 0x45, 0x49, 0x21, 0x78, 0xca, - 0xba, 0x70, 0x0e, 0x5d, 0xa9, 0x04, 0x7a, 0x0b, 0x7d, 0x4a, 0x02, 0x2a, 0xba, 0x42, 0xf6, 0xe8, - 0x1d, 0x15, 0x0a, 0x23, 0xa8, 0x30, 0x3a, 0x06, 0x76, 0x02, 0x83, 0xd1, 0x3a, 0x6e, 0xef, 0xd1, - 0x71, 0xdf, 0x00, 0x1c, 0xe8, 0xca, 0x44, 0xfb, 0xd7, 0xc5, 0xc7, 0x86, 0xed, 0x3a, 0x41, 0x17, - 0x30, 0xac, 0x0f, 0xa3, 0xdd, 0xeb, 0xe2, 0x41, 0x75, 0x94, 0xf6, 0x4e, 0x61, 0x8c, 0x5b, 0xef, - 0xc4, 0xf3, 0x47, 0xd9, 0xdb, 0xca, 0xb3, 0x87, 0xec, 0x2d, 0xba, 0x84, 0x71, 0xdd, 0xb5, 0xa2, - 0x6e, 0xdc, 0xeb, 0x56, 0xad, 0x0d, 0x6b, 0x1f, 0x4e, 0x0e, 0x65, 0xc6, 0x11, 0xa0, 0x1d, 0x61, - 0x04, 0x5e, 0x9b, 0x7b, 0x77, 0x06, 0x7d, 0x33, 0xe4, 0x91, 0x06, 0x30, 0x8b, 0xc3, 0x88, 0xdc, - 0x17, 0xec, 0x51, 0xc3, 0x0a, 0xa2, 0xca, 0x4e, 0xf4, 0x56, 0xa8, 0xe8, 0xa9, 0x11, 0xff, 0x08, - 0x5f, 0x08, 0xf6, 0x67, 0x1e, 0xd2, 0x92, 0xe7, 0x19, 0x61, 0x45, 0x1e, 0xc6, 0xa4, 0x48, 0xbc, - 0xd3, 0xce, 0xfd, 0x7e, 0xdd, 0x94, 0x2d, 0x54, 0xd5, 0x2a, 0x41, 0xdf, 0x41, 0x2b, 0x48, 0x8a, - 0x84, 0x48, 0xbe, 0xf1, 0xc6, 0xba, 0xc5, 0xb8, 0x49, 0xac, 0x92, 0x35, 0xdf, 0x28, 0xf6, 0x1a, - 0xdc, 0x7b, 0x35, 0xb1, 0xa6, 0x36, 0x36, 0x0b, 0xf4, 0x2b, 0x9c, 0x65, 0x79, 0x46, 0xda, 0x28, - 0x8a, 0x9a, 0xf7, 0x5a, 0xb7, 0xbf, 0x38, 0xdc, 0xcc, 0x65, 0x9e, 0xe1, 0x06, 0x4f, 0x55, 0x60, - 0x94, 0x75, 0x62, 0xe8, 0x0a, 0x06, 0x8c, 0x47, 0xfa, 0xa0, 0x48, 0x03, 0x9c, 0x1e, 0x00, 0x8c, - 0x9f, 0xb1, 0xc3, 0x78, 0xb4, 0xdc, 0xa7, 0x7e, 0x0a, 0xa8, 0x0b, 0x89, 0x2e, 0xe1, 0xb4, 0x45, - 0x84, 0x6e, 0x37, 0xda, 0xa9, 0x7d, 0x7c, 0xd2, 0x44, 0xdf, 0x6d, 0x37, 0xe8, 0xfb, 0x17, 0x38, - 0x9b, 0x0b, 0xf0, 0x0c, 0x2f, 0xff, 0x6f, 0x70, 0x97, 0xfb, 0xb4, 0xb9, 0x0b, 0x2d, 0x8f, 0x5a, - 0x9f, 0xf1, 0xe8, 0xd1, 0x13, 0x8f, 0x76, 0xa6, 0x69, 0x77, 0xa6, 0x59, 0x7b, 0xa4, 0xd7, 0xf2, - 0x88, 0xff, 0xbf, 0x05, 0x5f, 0x35, 0x7f, 0x62, 0x0d, 0xbb, 0x87, 0xec, 0x43, 0x2e, 0x52, 0xfd, - 0xd9, 0xcc, 0xc7, 0x6a, 0xcf, 0xe7, 0x12, 0x8e, 0x6b, 0x4b, 0x1c, 0x75, 0x2c, 0x31, 0x60, 0x95, - 0x11, 0x26, 0xe0, 0x1e, 0xca, 0xb4, 0x07, 0x2a, 0x62, 0x55, 0x5a, 0x8d, 0xbf, 0xab, 0x6d, 0xef, - 0x39, 0x6d, 0xaf, 0xa0, 0x65, 0x1c, 0x12, 0xd1, 0x92, 0x56, 0x37, 0xb5, 0xb5, 0xfb, 0x3d, 0x2d, - 0xe9, 0xdd, 0xcd, 0xef, 0xb3, 0x0d, 0x2f, 0xe3, 0x5d, 0x70, 0x1d, 0xe6, 0xe9, 0xec, 0xe1, 0xee, - 0xb7, 0xea, 0x09, 0x9e, 0x3d, 0xf3, 0xe6, 0x9a, 0x4c, 0xe0, 0xe8, 0xf7, 0xf5, 0xf6, 0x53, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x8f, 0xe8, 0x8e, 0x65, 0xc7, 0x07, 0x00, 0x00, + // 949 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x56, 0xcd, 0x8e, 0xe3, 0x44, + 0x10, 0x96, 0xe3, 0xd8, 0x99, 0x54, 0x3c, 0x33, 0xbb, 0xbd, 0x23, 0x8d, 0x35, 0xac, 0x96, 0x60, + 0x31, 0x4c, 0xe0, 0x30, 0x61, 0x33, 0x9c, 0xb8, 0x6d, 0x66, 0xa3, 0xdd, 0x08, 0x36, 0x8a, 0x3a, + 0x97, 0x15, 0x42, 0xb2, 0xda, 0x76, 0x6f, 0xdc, 0x4a, 0xfc, 0x43, 0xdb, 0x61, 0xc9, 0x05, 0x24, + 0x1e, 0x85, 0x23, 0x0f, 0xc1, 0x81, 0x23, 0x27, 0x9e, 0x81, 0x23, 0x4f, 0x81, 0xba, 0xdb, 0x7f, + 0x19, 0xcf, 0x2c, 0x97, 0xa4, 0xbb, 0xaa, 0xfa, 0xab, 0xea, 0xaf, 0xbe, 0xb2, 0x0d, 0x9f, 0x79, + 0xbe, 0x9f, 0xa5, 0xe3, 0xcc, 0x0f, 0x69, 0x44, 0xb3, 0x71, 0xb0, 0x4d, 0xd6, 0x63, 0x9f, 0xef, + 0xd3, 0x3c, 0x19, 0xb3, 0x80, 0x46, 0xec, 0xa7, 0xeb, 0x94, 0x27, 0x79, 0x82, 0x4c, 0xb5, 0xbb, + 0xf8, 0xea, 0xe1, 0xf8, 0x9c, 0x93, 0x38, 0xdb, 0x92, 0x3c, 0xe1, 0x63, 0x12, 0xf9, 0x5b, 0xf9, + 0xa3, 0x4e, 0x3b, 0x7f, 0x76, 0xe0, 0x74, 0x9e, 0x65, 0x3b, 0xca, 0x97, 0x3b, 0x6f, 0xcb, 0xfc, + 0x6f, 0xe8, 0x1e, 0x5d, 0xc1, 0x29, 0xc9, 0x73, 0xce, 0xbc, 0x5d, 0x4e, 0xdd, 0x98, 0x44, 0x34, + 0xb3, 0xb5, 0xa1, 0x3e, 0xea, 0xe3, 0x93, 0xca, 0xbc, 0x10, 0x56, 0xf4, 0x14, 0xba, 0xa1, 0x9b, + 0x6d, 0xec, 0xce, 0x50, 0x1b, 0x0d, 0x26, 0xfd, 0x6b, 0x89, 0x3b, 0xbb, 0x5d, 0x62, 0x3d, 0x5c, + 0x6d, 0xd0, 0x10, 0xcc, 0xd0, 0xe5, 0x24, 0x0e, 0x6c, 0xfd, 0xae, 0xdf, 0x08, 0x31, 0x89, 0x03, + 0xe4, 0x40, 0x2f, 0x74, 0x05, 0x66, 0x66, 0x77, 0x87, 0xfa, 0x61, 0x88, 0x19, 0xbe, 0x10, 0x0e, + 0x64, 0x83, 0xf6, 0xde, 0x36, 0x24, 0x00, 0x54, 0xde, 0x09, 0xd6, 0xde, 0x0b, 0x7c, 0x8f, 0x70, + 0x77, 0xfd, 0xdc, 0x36, 0x5b, 0xf8, 0x1e, 0xe1, 0xaf, 0x9e, 0x57, 0x11, 0x13, 0xbb, 0x77, 0x6f, + 0xc4, 0x04, 0x9d, 0x43, 0x2f, 0xe5, 0x49, 0xf2, 0xce, 0xf5, 0xed, 0xa3, 0xa1, 0x36, 0xb2, 0xb0, + 0x29, 0xb7, 0xb7, 0xb5, 0x23, 0xb3, 0xfb, 0x0d, 0xc7, 0x0a, 0x21, 0xe8, 0x86, 0x24, 0x0b, 0x6d, + 0x90, 0x56, 0xb9, 0x76, 0x5e, 0x43, 0x5f, 0x71, 0x28, 0xd8, 0x7b, 0x04, 0x3a, 0xcb, 0x36, 0xb6, + 0x26, 0xfd, 0x62, 0x89, 0x3e, 0x07, 0x9d, 0xa5, 0x25, 0x4b, 0xe7, 0xd7, 0x45, 0xf7, 0xee, 0xb0, + 0x8e, 0x45, 0x8c, 0x93, 0x02, 0xdc, 0x72, 0x1a, 0xd0, 0x38, 0x67, 0x64, 0x8b, 0xce, 0x41, 0x23, + 0x12, 0xe8, 0xa0, 0x74, 0x8d, 0x08, 0x87, 0xd7, 0x66, 0x5d, 0xf3, 0x90, 0x05, 0x1a, 0x95, 0x74, + 0x5b, 0x58, 0xa3, 0x62, 0x27, 0x98, 0x95, 0xbb, 0x0c, 0x9d, 0x81, 0xa1, 0xb8, 0x36, 0x86, 0xfa, + 0xc8, 0xc2, 0x6a, 0xe3, 0xfc, 0x02, 0x03, 0x91, 0x11, 0xd3, 0x1f, 0x76, 0x34, 0xcb, 0xd1, 0x47, + 0xa0, 0xc7, 0xfb, 0xa8, 0x9d, 0x54, 0x58, 0xd1, 0x27, 0x60, 0x31, 0x59, 0xb5, 0x1b, 0x27, 0xb1, + 0x4f, 0x65, 0x05, 0x16, 0x1e, 0x28, 0xdb, 0x42, 0x98, 0x9a, 0x84, 0xea, 0x0f, 0x11, 0xda, 0x6d, + 0x12, 0xea, 0xcc, 0xc0, 0x9c, 0xcd, 0x5f, 0x2e, 0xf6, 0xd1, 0x87, 0x73, 0x3f, 0x83, 0x41, 0x71, + 0xde, 0xa5, 0x2c, 0x28, 0x52, 0xf7, 0x15, 0xc6, 0x8c, 0x05, 0xce, 0x14, 0x0c, 0xfc, 0xfa, 0x7f, + 0x51, 0x9e, 0x02, 0x94, 0x28, 0x3c, 0x2c, 0x40, 0x8e, 0x14, 0x08, 0x0e, 0x9d, 0x3f, 0x0c, 0xe8, + 0xaf, 0xd8, 0x3a, 0x26, 0xf9, 0x8e, 0x53, 0xa1, 0x4e, 0xe2, 0xa6, 0x9c, 0x45, 0xb4, 0x0d, 0x66, + 0x92, 0xa5, 0x70, 0xa0, 0x67, 0x60, 0x10, 0xd7, 0x23, 0xbc, 0xdd, 0x8c, 0x2e, 0x99, 0x12, 0x2e, + 0x30, 0xbc, 0x02, 0xa3, 0x35, 0x04, 0xa6, 0xa7, 0x30, 0x1a, 0x94, 0x75, 0x0f, 0x28, 0x6b, 0x14, + 0x9b, 0x6d, 0xe4, 0x0c, 0x54, 0xc5, 0xae, 0x36, 0xe8, 0x02, 0xfa, 0x15, 0x21, 0x72, 0x02, 0x2c, + 0xdc, 0x2b, 0xe8, 0x38, 0xb8, 0xa6, 0x12, 0x7f, 0x7d, 0xcd, 0xc9, 0x81, 0xf7, 0xa6, 0xd0, 0x7d, + 0xe9, 0xbd, 0x41, 0x97, 0x70, 0x5a, 0x65, 0x2d, 0x4a, 0x57, 0x13, 0x60, 0x15, 0xa9, 0x55, 0xd5, + 0x0e, 0x1c, 0x97, 0x61, 0x4a, 0x55, 0x20, 0x55, 0xa5, 0x9a, 0xb4, 0x52, 0xb3, 0x7b, 0x06, 0x86, + 0x12, 0xca, 0x40, 0x02, 0xa8, 0x4d, 0xd9, 0x20, 0xeb, 0x01, 0x89, 0x55, 0xb0, 0xdc, 0x15, 0x61, + 0xc7, 0xf2, 0x28, 0x14, 0xe5, 0x89, 0x06, 0x7f, 0x0d, 0x4f, 0x38, 0xfd, 0x31, 0xf1, 0x49, 0xce, + 0x92, 0xd8, 0xa5, 0x69, 0xe2, 0x87, 0x6e, 0xba, 0xb1, 0x4f, 0x5a, 0xcf, 0x88, 0xc7, 0x75, 0xd8, + 0x4c, 0x44, 0x2d, 0x37, 0xe8, 0x0b, 0x68, 0x18, 0xdd, 0x74, 0xe3, 0x66, 0x6c, 0x6d, 0x9f, 0xca, + 0x14, 0xa7, 0xb5, 0x63, 0xb9, 0x59, 0xb1, 0xb5, 0xa8, 0x5e, 0x82, 0xdb, 0x8f, 0x86, 0xda, 0x48, + 0xc7, 0x6a, 0x83, 0xbe, 0x85, 0xb3, 0x38, 0x89, 0xdd, 0x26, 0x8a, 0x28, 0xcd, 0x7e, 0x2c, 0xd3, + 0x5f, 0x94, 0xd3, 0xbd, 0x48, 0x62, 0x5c, 0xe3, 0x89, 0x08, 0x8c, 0xe2, 0x96, 0x0d, 0x5d, 0x41, + 0x8f, 0xb2, 0x40, 0x5e, 0x14, 0x49, 0x80, 0x93, 0x12, 0x40, 0xcd, 0x04, 0x36, 0x29, 0x0b, 0xc4, + 0xa5, 0x3f, 0x05, 0x93, 0x87, 0x32, 0xee, 0x89, 0x8c, 0x3b, 0x2e, 0xe3, 0xa4, 0xe8, 0xb1, 0xc1, + 0xc3, 0xc5, 0x3e, 0x72, 0x22, 0x40, 0xed, 0xc4, 0xe8, 0x12, 0x4e, 0x1a, 0xe5, 0x92, 0xed, 0x5a, + 0xea, 0xd9, 0xc0, 0xc7, 0xb5, 0xf5, 0xc5, 0x76, 0x8d, 0xbe, 0x7c, 0xe0, 0x66, 0x6a, 0x4a, 0xee, + 0xa9, 0xde, 0xf9, 0x19, 0xac, 0xc5, 0x3e, 0xaa, 0x27, 0xa6, 0xa1, 0x64, 0xed, 0x03, 0x4a, 0xee, + 0xdc, 0x51, 0x72, 0xab, 0xe7, 0x7a, 0xab, 0xe7, 0x95, 0x92, 0xba, 0x0d, 0x25, 0x39, 0x7f, 0x6b, + 0xf0, 0x71, 0xfd, 0xb8, 0xac, 0xab, 0x9b, 0xc7, 0xef, 0x12, 0x1e, 0xc9, 0x65, 0xdd, 0x45, 0xad, + 0xd9, 0xc5, 0x4b, 0x38, 0xaa, 0x84, 0xd3, 0x69, 0x09, 0xa7, 0x47, 0x0b, 0xb9, 0x0c, 0xc1, 0x2a, + 0xc3, 0xa4, 0x52, 0x8a, 0xc2, 0x0a, 0xb7, 0x10, 0x49, 0x9b, 0xdb, 0xee, 0x7d, 0xdc, 0x5e, 0x41, + 0x43, 0x5e, 0x6e, 0x40, 0x72, 0x52, 0xcc, 0x73, 0xe3, 0xf4, 0x4b, 0x92, 0x93, 0xe9, 0xaf, 0x1a, + 0x80, 0x9f, 0x44, 0x45, 0x77, 0xa7, 0x83, 0xb9, 0xfc, 0x5f, 0x8a, 0x77, 0xf5, 0x52, 0xfb, 0x6e, + 0xbc, 0x66, 0x79, 0xb8, 0xf3, 0xae, 0xfd, 0x24, 0x1a, 0xcf, 0xa7, 0x6f, 0x8a, 0x0f, 0x81, 0xf1, + 0x3d, 0x6f, 0x7e, 0xe5, 0xf9, 0xad, 0xa3, 0xcf, 0xdf, 0xbe, 0xfd, 0xbd, 0x63, 0x2a, 0x98, 0xbf, + 0xca, 0xc5, 0x3f, 0x1d, 0xa4, 0x16, 0xdf, 0xbf, 0x5a, 0x4e, 0xdf, 0xd0, 0x9c, 0x88, 0x8a, 0xfe, + 0x2d, 0xbd, 0x9e, 0x29, 0xbf, 0x0d, 0x6e, 0xfe, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x36, 0xd7, + 0xe8, 0x83, 0x08, 0x00, 0x00, } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.proto b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.proto index b42fbb215b1..3e11e35ebbc 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.proto +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/idemix.proto @@ -66,11 +66,22 @@ message CredRequest { bytes proof_s = 4; } +// EIDNym specifies a pseudonymous enrollment id object that consists of +// nym - pseudonymous enrollment id +// s_eid - field element message EIDNym { amcl.ECP nym = 1; bytes proof_s_eid = 2; } +// RHNym specifies a pseudonymous revocation handle object that consists of +// nym - pseudonymous revocation handle +// s_rh - field element +message RHNym { + amcl.ECP nym = 1; + bytes proof_s_rh = 2; +} + // Signature specifies a signature object that consists of // a_prime, a_bar, b_prime, proof_* - randomized credential signature values // and a zero-knowledge proof of knowledge of a credential @@ -96,6 +107,7 @@ message Signature { int64 epoch = 16; NonRevocationProof non_revocation_proof = 17; EIDNym eid_nym = 18; + RHNym rh_nym = 19; } // NonRevocationProof contains proof that the credential is not revoked diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/issuerkey.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/issuerkey.go index 3ee5d483ac0..ffae2fc2750 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/issuerkey.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/issuerkey.go @@ -88,7 +88,7 @@ func newIssuerKey(AttributeNames []string, rng io.Reader, curve *math.Curve, t T t2 := BarG1.Mul(r) // t2 = (\bar g_1)^r, cover BarG2 // Step 2: Compute the Fiat-Shamir hash, forming the challenge of the ZKP. - proofData := make([]byte, 18*curve.FieldBytes+3) + proofData := make([]byte, 3*curve.G1ByteSize+3*curve.G2ByteSize) index := 0 index = appendBytesG2(proofData, index, t1) index = appendBytesG1(proofData, index, t2) @@ -194,7 +194,7 @@ func (IPk *IssuerPublicKey) Check(curve *math.Curve, t Translator) error { // Verify Proof // Recompute challenge - proofData := make([]byte, 18*curve.FieldBytes+3) + proofData := make([]byte, 3*curve.G1ByteSize+3*curve.G2ByteSize) index := 0 // Recompute t-values using s-values diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymeid.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymeid.go new file mode 100644 index 00000000000..c0131bac757 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymeid.go @@ -0,0 +1,59 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package idemix + +import ( + math "github.com/IBM/mathlib" + "github.com/pkg/errors" +) + +type NymEID []byte + +func (nym NymEID) AuditNymEid( + ipk *IssuerPublicKey, + eidAttr *math.Zr, + eidIndex int, + RNymEid *math.Zr, + curve *math.Curve, + t Translator, +) error { + // Validate inputs + if ipk == nil { + return errors.Errorf("cannot verify idemix signature: received nil input") + } + + if len(nym) == 0 { + return errors.Errorf("no EidNym provided") + } + + if len(ipk.HAttrs) <= eidIndex { + return errors.Errorf("could not access H_a_eid in array") + } + + H_a_eid, err := t.G1FromProto(ipk.HAttrs[eidIndex]) + if err != nil { + return errors.Wrap(err, "could not deserialize H_a_eid") + } + + HRand, err := t.G1FromProto(ipk.HRand) + if err != nil { + return errors.Wrap(err, "could not deserialize HRand") + } + + EidNym, err := curve.NewG1FromBytes(nym) + if err != nil { + return errors.Wrap(err, "could not deserialize EidNym") + } + + Nym_eid := H_a_eid.Mul2(eidAttr, HRand, RNymEid) + + if !Nym_eid.Equals(EidNym) { + return errors.New("eid nym does not match") + } + + return nil +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymrh.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymrh.go new file mode 100644 index 00000000000..11017ac9bde --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymrh.go @@ -0,0 +1,59 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package idemix + +import ( + math "github.com/IBM/mathlib" + "github.com/pkg/errors" +) + +type NymRH []byte + +func (nym NymRH) AuditNymRh( + ipk *IssuerPublicKey, + rhAttr *math.Zr, + rhIndex int, + RNymRh *math.Zr, + curve *math.Curve, + t Translator, +) error { + // Validate inputs + if ipk == nil { + return errors.Errorf("cannot verify idemix signature: received nil input") + } + + if len(nym) == 0 { + return errors.Errorf("no RhNym provided") + } + + if len(ipk.HAttrs) <= rhIndex { + return errors.Errorf("could not access H_a_rh in array") + } + + H_a_rh, err := t.G1FromProto(ipk.HAttrs[rhIndex]) + if err != nil { + return errors.Wrap(err, "could not deserialize H_a_rh") + } + + HRand, err := t.G1FromProto(ipk.HRand) + if err != nil { + return errors.Wrap(err, "could not deserialize HRand") + } + + RhNym, err := curve.NewG1FromBytes(nym) + if err != nil { + return errors.Wrap(err, "could not deserialize RhNym") + } + + Nym_rh := H_a_rh.Mul2(rhAttr, HRand, RNymRh) + + if !Nym_rh.Equals(RhNym) { + return errors.New("rh nym does not match") + } + + return nil +} diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymsignature.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymsignature.go index 713486cc8c3..3e40fbc6a83 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymsignature.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/nymsignature.go @@ -54,20 +54,20 @@ func newNymSignature(sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk *IssuerPublic // - one bigint (hash of the issuer public key) of length math.FieldBytes // - disclosed attributes // - message being signed - proofData := make([]byte, len([]byte(signLabel))+2*(2*curve.FieldBytes+1)+curve.FieldBytes+len(msg)) + proofData := make([]byte, len([]byte(signLabel))+2*curve.G1ByteSize+curve.ScalarByteSize+len(msg)) index := 0 index = appendBytesString(proofData, index, signLabel) index = appendBytesG1(proofData, index, t) index = appendBytesG1(proofData, index, Nym) copy(proofData[index:], ipk.Hash) - index = index + curve.FieldBytes + index = index + curve.ScalarByteSize copy(proofData[index:], msg) c := curve.HashToZr(proofData) // combine the previous hash and the nonce and hash again to compute the final Fiat-Shamir value 'ProofC' index = 0 - proofData = proofData[:2*curve.FieldBytes] + proofData = proofData[:2*curve.ScalarByteSize] index = appendBytesBig(proofData, index, c) - index = appendBytesBig(proofData, index, Nonce) + appendBytesBig(proofData, index, Nonce) ProofC := curve.HashToZr(proofData) // Step 3: reply to the challenge message (s-values) @@ -106,19 +106,19 @@ func (sig *NymSignature) Ver(nym *math.G1, ipk *IssuerPublicKey, msg []byte, cur t.Sub(nym.Mul(ProofC)) // t = h_{sk}^{s_{sk} \ cdot h_r^{s_{RNym} // Recompute challenge - proofData := make([]byte, len([]byte(signLabel))+2*(2*curve.FieldBytes+1)+curve.FieldBytes+len(msg)) + proofData := make([]byte, len([]byte(signLabel))+2*curve.G1ByteSize+curve.ScalarByteSize+len(msg)) index := 0 index = appendBytesString(proofData, index, signLabel) index = appendBytesG1(proofData, index, t) index = appendBytesG1(proofData, index, nym) copy(proofData[index:], ipk.Hash) - index = index + curve.FieldBytes + index = index + curve.ScalarByteSize copy(proofData[index:], msg) c := curve.HashToZr(proofData) index = 0 - proofData = proofData[:2*curve.FieldBytes] + proofData = proofData[:2*curve.ScalarByteSize] index = appendBytesBig(proofData, index, c) - index = appendBytesBig(proofData, index, Nonce) + appendBytesBig(proofData, index, Nonce) if !ProofC.Equals(curve.HashToZr(proofData)) { return errors.Errorf("pseudonym signature invalid: zero-knowledge proof is invalid") diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/revocation_authority.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/revocation_authority.go index a50fa376138..2b8572ca5cc 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/revocation_authority.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/revocation_authority.go @@ -16,6 +16,7 @@ import ( "math/big" amcl "github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl" + weakbb "github.com/IBM/idemix/bccsp/schemes/weak-bb" math "github.com/IBM/mathlib" "github.com/golang/protobuf/proto" "github.com/pkg/errors" @@ -75,7 +76,7 @@ func createCRI(key *ecdsa.PrivateKey, unrevokedHandles []*math.Zr, epoch int, al cri.EpochPk = t.G2ToProto(curve.GenG2) } else { // create epoch key - _, epochPk := wbbKeyGen(curve, rng) + _, epochPk := weakbb.WbbKeyGen(curve, rng) cri.EpochPk = t.G2ToProto(epochPk) } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/signature.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/signature.go index d2eddbbe33a..9312876e65c 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/signature.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/signature.go @@ -12,7 +12,7 @@ import ( "io" "sort" - opts "github.com/IBM/idemix/bccsp/schemes" + opts "github.com/IBM/idemix/bccsp/types" math "github.com/IBM/mathlib" "github.com/pkg/errors" ) @@ -20,6 +20,7 @@ import ( // signLabel is the label used in zero-knowledge proof (ZKP) to identify that this ZKP is a signature of knowledge const signLabel = "sign" const signWithEidNymLabel = "signWithEidNym" +const signWithEidNymRhNymLabel = "signWithEidNymRhNym" // When the revocation handle is present the enrollment id must also be present // A signature that is produced using an Identity Mixer credential is a so-called signature of knowledge // (for details see C.P.Schnorr "Efficient Identification and Signatures for Smart Cards") @@ -56,24 +57,73 @@ func (i *Idemix) NewSignature( Nym *math.G1, RNym *math.Zr, ipk *IssuerPublicKey, - Disclosure []byte, - msg []byte, + Disclosure, msg []byte, rhIndex, eidIndex int, cri *CredentialRevocationInformation, rng io.Reader, tr Translator, sigType opts.SignatureType, + metadata *opts.IdemixSignerMetadata, ) (*Signature, *opts.IdemixSignerMetadata, error) { switch sigType { - case opts.Standard: - return newSignature(cred, sk, Nym, RNym, ipk, Disclosure, msg, rhIndex, cri, rng, i.Curve, tr) - case opts.EidNym: - return newSignatureWithEIDNym(cred, sk, Nym, RNym, ipk, Disclosure, msg, rhIndex, eidIndex, cri, rng, i.Curve, tr) + case opts.Standard: // Generation of standard signature + return newSignature(cred, sk, Nym, RNym, ipk, Disclosure, msg, rhIndex, cri, rng, i.Curve, tr, metadata) + case opts.EidNym: // Generation of pseudonymous eid signature + return newSignatureWithEIDNym(cred, sk, Nym, RNym, ipk, Disclosure, msg, rhIndex, eidIndex, cri, rng, i.Curve, tr, metadata) + case opts.EidNymRhNym: // Generation of pseudonymous eid and rh signature + return newSignatureWithEIDNymAndRHNym(cred, sk, Nym, RNym, ipk, Disclosure, msg, rhIndex, eidIndex, cri, rng, i.Curve, tr, metadata) } panic(fmt.Sprintf("programming error, requested signature type %d", sigType)) } +func newSignature( + cred *Credential, + sk *math.Zr, + Nym *math.G1, + RNym *math.Zr, + ipk *IssuerPublicKey, + Disclosure []byte, + msg []byte, + rhIndex int, + cri *CredentialRevocationInformation, + rng io.Reader, + curve *math.Curve, + tr Translator, + metadata *opts.IdemixSignerMetadata, +) (*Signature, *opts.IdemixSignerMetadata, error) { + t1, t2, t3, APrime, ABar, BPrime, nonRevokedProofHashData, E, Nonce, rSk, rSPrime, rR2, rR3, r2, r3, re, sPrime, rRNym, rAttrs, prover, HiddenIndices, err := prepare(cred, sk, Nym, RNym, ipk, Disclosure, msg, rhIndex, cri, rng, curve, tr) + if err != nil { + return nil, nil, err + } + + return finalise( + cred, + sk, + Nym, + RNym, + ipk, + Disclosure, + msg, + rhIndex, -1, + cri, + rng, + curve, + tr, + t1, t2, t3, + APrime, ABar, BPrime, + nonRevokedProofHashData, + E, + Nonce, + rSk, rSPrime, rR2, rR3, r2, r3, re, sPrime, rRNym, + rAttrs, + prover, + HiddenIndices, + opts.Standard, + metadata, + ) +} + func newSignatureWithEIDNym( cred *Credential, sk *math.Zr, @@ -87,6 +137,7 @@ func newSignatureWithEIDNym( rng io.Reader, curve *math.Curve, tr Translator, + metadata *opts.IdemixSignerMetadata, ) (*Signature, *opts.IdemixSignerMetadata, error) { if Disclosure[eidIndex] != 0 { return nil, nil, errors.Errorf("cannot create idemix signature: disclosure of enrollment ID requested for NewSignatureWithEIDNym") @@ -120,10 +171,11 @@ func newSignatureWithEIDNym( prover, HiddenIndices, opts.EidNym, + metadata, ) } -func newSignature( +func newSignatureWithEIDNymAndRHNym( cred *Credential, sk *math.Zr, Nym *math.G1, @@ -131,12 +183,21 @@ func newSignature( ipk *IssuerPublicKey, Disclosure []byte, msg []byte, - rhIndex int, + rhIndex, eidIndex int, cri *CredentialRevocationInformation, rng io.Reader, curve *math.Curve, tr Translator, + metadata *opts.IdemixSignerMetadata, ) (*Signature, *opts.IdemixSignerMetadata, error) { + if Disclosure[eidIndex] != 0 { + return nil, nil, errors.Errorf("cannot create idemix signature: disclosure of enrollment ID requested for NewSignatureWithEIDNym") + } + + if Disclosure[rhIndex] != 0 { + return nil, nil, errors.Errorf("cannot create idemix signature: disclosure of revocation handle requested for NewSignatureWithEIDNymAndRHNym") + } + t1, t2, t3, APrime, ABar, BPrime, nonRevokedProofHashData, E, Nonce, rSk, rSPrime, rR2, rR3, r2, r3, re, sPrime, rRNym, rAttrs, prover, HiddenIndices, err := prepare(cred, sk, Nym, RNym, ipk, Disclosure, msg, rhIndex, cri, rng, curve, tr) if err != nil { return nil, nil, err @@ -150,7 +211,7 @@ func newSignature( ipk, Disclosure, msg, - rhIndex, -1, + rhIndex, eidIndex, cri, rng, curve, @@ -164,7 +225,8 @@ func newSignature( rAttrs, prover, HiddenIndices, - opts.Standard, + opts.EidNymRhNym, + metadata, ) } @@ -365,33 +427,99 @@ func finalise( prover nonRevokedProver, HiddenIndices []int, sigType opts.SignatureType, + metadata *opts.IdemixSignerMetadata, ) (*Signature, *opts.IdemixSignerMetadata, error) { - var Nym_eid *math.G1 - var t4 *math.G1 - var r_r_eid, r_eid *math.Zr - if sigType == opts.EidNym { + var Nym_eid, Nym_rh *math.G1 + var t4_eid, t4_rh *math.G1 + var r_r_eid, r_eid, r_r_rh, r_rh *math.Zr + var EID, RH *math.Zr + var err error + + if sigType == opts.EidNym || sigType == opts.EidNymRhNym { + EID = curve.NewZrFromBytes(cred.Attrs[eidIndex]) + if metadata != nil { + if metadata.EidNymAuditData == nil { + return nil, nil, errors.Errorf("invalid argument, expected metadata") + } + + if !metadata.EidNymAuditData.Attr.Equals(EID) { + return nil, nil, errors.Errorf("invalid argument, eid nym audit metadata does not match (1)") + } + r_eid = metadata.EidNymAuditData.Rand + } else { + r_eid = curve.NewRandomZr(rng) + } + r_a_eid := rAttrs[sort.SearchInts(HiddenIndices, eidIndex)] H_a_eid, err := tr.G1FromProto(ipk.HAttrs[eidIndex]) if err != nil { return nil, nil, err } - a_eid := curve.NewZrFromBytes(cred.Attrs[eidIndex]) + a_eid := EID HRand, err := tr.G1FromProto(ipk.HRand) if err != nil { return nil, nil, err } - // Generate new required randomness r_eid and r_r_eid - r_eid = curve.NewRandomZr(rng) + // Generate new required randomness r_r_eid r_r_eid = curve.NewRandomZr(rng) // Nym_eid is a hiding and binding commitment to the enrollment id Nym_eid = H_a_eid.Mul2(a_eid, HRand, r_eid) // H_{a_{eid}}^{a_{eid}} \cdot H_{r}^{r_{eid}} + if metadata != nil { + if !metadata.EidNymAuditData.Nym.Equals(Nym_eid) { + return nil, nil, errors.Errorf("invalid argument, eid nym audit metadata does not match (2)") + } + } + // t4 is the new t-value for the eid nym computed above - t4 = H_a_eid.Mul2(r_a_eid, HRand, r_r_eid) // H_{a_{eid}}^{r_{a_{2}}} \cdot H_{r}^{r_{r_{eid}}} + t4_eid = H_a_eid.Mul2(r_a_eid, HRand, r_r_eid) // H_{a_{eid}}^{r_{a_{2}}} \cdot H_{r}^{r_{r_{eid}}} + } + + if sigType == opts.EidNymRhNym { + RH = curve.NewZrFromBytes(cred.Attrs[rhIndex]) + if metadata != nil { + if metadata.RhNymAuditData == nil { + return nil, nil, errors.Errorf("invalid argument, expected metadata") + } + + if !metadata.RhNymAuditData.Attr.Equals(RH) { + return nil, nil, errors.Errorf("invalid argument, rh nym audit metadata does not match (1)") + } + r_rh = metadata.RhNymAuditData.Rand + } else { + r_rh = curve.NewRandomZr(rng) + } + + r_a_rh := rAttrs[sort.SearchInts(HiddenIndices, rhIndex)] + H_a_rh, err := tr.G1FromProto(ipk.HAttrs[rhIndex]) + if err != nil { + return nil, nil, err + } + + a_rh := RH + HRand, err := tr.G1FromProto(ipk.HRand) + if err != nil { + return nil, nil, err + } + + // Generate new required randomness r_r_rh + r_r_rh = curve.NewRandomZr(rng) + + // Nym_rh is a hiding and binding commitment to the revocation handle + Nym_rh = H_a_rh.Mul2(a_rh, HRand, r_rh) // H_{a_{rh}}^{a_{rh}} \cdot H_{r}^{r_{rh}} + + if metadata != nil { + if !metadata.RhNymAuditData.Nym.Equals(Nym_rh) { + return nil, nil, errors.Errorf("invalid argument, rh nym audit metadata does not match (2)") + } + } + + // t4 is the new t-value for the rh nym computed above + t4_rh = H_a_rh.Mul2(r_a_rh, HRand, r_r_rh) // H_{a_{rh}}^{r_{a_{2}}} \cdot H_{r}^{r_{r_{rh}}} } // Step 2: Compute the Fiat-Shamir hash, forming the challenge of the ZKP. @@ -403,10 +531,17 @@ func finalise( // one bigint (hash of the issuer public key) of length math.FieldBytes // disclosed attributes // message being signed - // the amount of bytes needed for the nonrevocation proof - pdl := len([]byte(signLabel)) + 7*(2*curve.FieldBytes+1) + curve.FieldBytes + len(Disclosure) + len(msg) + ProofBytes[RevocationAlgorithm(cri.RevocationAlg)] - if sigType == opts.EidNym { - pdl = len([]byte(signWithEidNymLabel)) + 9*(2*curve.FieldBytes+1) + curve.FieldBytes + len(Disclosure) + len(msg) + ProofBytes[RevocationAlgorithm(cri.RevocationAlg)] + // the minimum amount of bytes needed for the nonrevocation proof + pdl := curve.ScalarByteSize + len(Disclosure) + len(msg) + ProofBytes[RevocationAlgorithm(cri.RevocationAlg)] + switch sigType { + case opts.Standard: // additional bytes for a standard sign label + pdl += len([]byte(signLabel)) + 7*curve.G1ByteSize + case opts.EidNym: // additional bytes for a sign label including an enrollment id attribute + pdl += len([]byte(signWithEidNymLabel)) + 9*curve.G1ByteSize + case opts.EidNymRhNym: // additional bytes for a sign label including both an enrollment id and a revocation handle attribute + pdl += len([]byte(signWithEidNymRhNymLabel)) + 11*curve.G1ByteSize + default: + panic("programming error") } proofData := make([]byte, pdl) index := 0 @@ -415,6 +550,8 @@ func finalise( index = appendBytesString(proofData, index, signLabel) case opts.EidNym: index = appendBytesString(proofData, index, signWithEidNymLabel) + case opts.EidNymRhNym: + index = appendBytesString(proofData, index, signWithEidNymRhNymLabel) default: panic("programming error") } @@ -425,13 +562,17 @@ func finalise( index = appendBytesG1(proofData, index, ABar) index = appendBytesG1(proofData, index, BPrime) index = appendBytesG1(proofData, index, Nym) - if sigType == opts.EidNym { + if sigType == opts.EidNym || sigType == opts.EidNymRhNym { index = appendBytesG1(proofData, index, Nym_eid) - index = appendBytesG1(proofData, index, t4) + index = appendBytesG1(proofData, index, t4_eid) + } + if sigType == opts.EidNymRhNym { + index = appendBytesG1(proofData, index, Nym_rh) + index = appendBytesG1(proofData, index, t4_rh) } index = appendBytes(proofData, index, nonRevokedProofHashData) copy(proofData[index:], ipk.Hash) - index = index + curve.FieldBytes + index = index + curve.ScalarByteSize copy(proofData[index:], Disclosure) index = index + len(Disclosure) copy(proofData[index:], msg) @@ -439,7 +580,7 @@ func finalise( // add the previous hash and the nonce and hash again to compute a second hash (C value) index = 0 - proofData = proofData[:2*curve.FieldBytes] + proofData = proofData[:2*curve.ScalarByteSize] index = appendBytesBig(proofData, index, c) appendBytesBig(proofData, index, Nonce) ProofC := curve.HashToZr(proofData) @@ -522,7 +663,7 @@ func finalise( NonRevocationProof: nonRevokedProof, } - if sigType == opts.EidNym { + if sigType == opts.EidNym || sigType == opts.EidNymRhNym { ProofSEid := curve.ModAdd(r_r_eid, curve.ModMul(ProofC, r_eid, curve.GroupOrder), curve.GroupOrder) // s_{r{eid}} = r_r_eid + C \cdot r_eid sig.EidNym = &EIDNym{ Nym: tr.G1ToProto(Nym_eid), @@ -530,12 +671,36 @@ func finalise( } } + if sigType == opts.EidNymRhNym { + ProofSRh := curve.ModAdd(r_r_rh, curve.ModMul(ProofC, r_rh, curve.GroupOrder), curve.GroupOrder) + sig.RhNym = &RHNym{ + Nym: tr.G1ToProto(Nym_rh), + ProofSRh: ProofSRh.Bytes(), + } + } + var m *opts.IdemixSignerMetadata if sigType == opts.EidNym { m = &opts.IdemixSignerMetadata{ - NymEIDAuditData: &opts.NymEIDAuditData{ - RNymEid: r_eid, - EID: curve.NewZrFromBytes(cred.Attrs[eidIndex]), + EidNymAuditData: &opts.AttrNymAuditData{ + Nym: Nym_eid, + Rand: r_eid, + Attr: EID, + }, + } + } + + if sigType == opts.EidNymRhNym { + m = &opts.IdemixSignerMetadata{ + EidNymAuditData: &opts.AttrNymAuditData{ + Nym: Nym_eid, + Rand: r_eid, + Attr: EID, + }, + RhNymAuditData: &opts.AttrNymAuditData{ + Nym: Nym_rh, + Rand: r_rh, + Attr: RH, }, } } @@ -588,6 +753,51 @@ func (sig *Signature) AuditNymEid( return nil } +func (sig *Signature) AuditNymRh( + ipk *IssuerPublicKey, + rhAttr *math.Zr, + rhIndex int, + RNymRh *math.Zr, + curve *math.Curve, + t Translator, +) error { + // Validate inputs + if ipk == nil { + return errors.Errorf("cannot verify idemix signature: received nil input") + } + + if sig.RhNym == nil || sig.RhNym.Nym == nil { + return errors.Errorf("no RhNym provided") + } + + if len(ipk.HAttrs) <= rhIndex { + return errors.Errorf("could not access H_a_rh in array") + } + + H_a_rh, err := t.G1FromProto(ipk.HAttrs[rhIndex]) + if err != nil { + return errors.Wrap(err, "could not deserialize H_a_rh") + } + + HRand, err := t.G1FromProto(ipk.HRand) + if err != nil { + return errors.Wrap(err, "could not deserialize HRand") + } + + RhNym, err := t.G1FromProto(sig.RhNym.Nym) + if err != nil { + return errors.Wrap(err, "could not deserialize RhNym") + } + + Nym_rh := H_a_rh.Mul2(rhAttr, HRand, RNymRh) + + if !Nym_rh.Equals(RhNym) { + return errors.New("rh nym does not match") + } + + return nil +} + // Ver verifies an idemix signature // Disclosure steers which attributes it expects to be disclosed // attributeValues contains the desired attribute values. @@ -606,7 +816,7 @@ func (sig *Signature) Ver( meta *opts.IdemixSignerMetadata, ) error { // Validate inputs - if ipk == nil || revPk == nil { + if ipk == nil { return errors.Errorf("cannot verify idemix signature: received nil input") } @@ -617,17 +827,31 @@ func (sig *Signature) Ver( if sig.NonRevocationProof.RevocationAlg != int32(ALG_NO_REVOCATION) && Disclosure[rhIndex] == 1 { return errors.Errorf("Attribute %d is disclosed but is also used as revocation handle, which should remain hidden.", rhIndex) } - if verType == opts.ExpectEidNym && (sig.EidNym == nil || sig.EidNym.Nym == nil || sig.EidNym.ProofSEid == nil) { return errors.Errorf("no EidNym provided but ExpectEidNym required") } - if verType == opts.ExpectStandard && sig.EidNym != nil { - return errors.Errorf("EidNym available but ExpectStandard required") + if verType == opts.ExpectEidNymRhNym { + if sig.EidNym == nil || sig.EidNym.Nym == nil || sig.EidNym.ProofSEid == nil { + return errors.Errorf("no EidNym provided but ExpectEidNymRhNym required") + } + if sig.RhNym == nil || sig.RhNym.Nym == nil || sig.RhNym.ProofSRh == nil { + return errors.Errorf("no RhNym provided but ExpectEidNymRhNym required") + } + } + + if verType == opts.ExpectStandard { + if sig.RhNym != nil { + return errors.Errorf("RhNym available but ExpectStandard required") + } + if sig.EidNym != nil { + return errors.Errorf("EidNym available but ExpectStandard required") + } } - verifyEIDNym := (verType == opts.BestEffort && sig.EidNym != nil) || verType == opts.ExpectEidNym + verifyRHNym := (verType == opts.BestEffort && sig.RhNym != nil) || verType == opts.ExpectEidNymRhNym + verifyEIDNym := (verType == opts.BestEffort && sig.EidNym != nil) || verType == opts.ExpectEidNym || verType == opts.ExpectEidNymRhNym || verifyRHNym HiddenIndices := hiddenIndices(Disclosure) @@ -664,7 +888,6 @@ func (sig *Signature) Ver( ProofSSPrime := curve.NewZrFromBytes(sig.GetProofSSPrime()) ProofSRNym := curve.NewZrFromBytes(sig.GetProofSRNym()) ProofSAttrs := make([]*math.Zr, len(sig.GetProofSAttrs())) - if len(sig.ProofSAttrs) != len(HiddenIndices) { return errors.Errorf("signature invalid: incorrect amount of s-values for AttributeProofSpec") } @@ -715,7 +938,6 @@ func (sig *Signature) Ver( return err } } - // Recompute t1 t1 := APrime.Mul2(ProofSE, HRand, ProofSR2) temp := curve.NewG1() @@ -745,21 +967,35 @@ func (sig *Signature) Ver( t3 := HSk.Mul2(ProofSSk, HRand, ProofSRNym) t3.Sub(Nym.Mul(ProofC)) - var t4 *math.G1 + // Attribute pseudonym extension signature verification + var t4_eid *math.G1 if verifyEIDNym { H_a_eid, err := t.G1FromProto(ipk.HAttrs[eidIndex]) if err != nil { return err } - t4 = H_a_eid.Mul2(ProofSAttrs[sort.SearchInts(HiddenIndices, eidIndex)], HRand, curve.NewZrFromBytes(sig.EidNym.ProofSEid)) + t4_eid = H_a_eid.Mul2(ProofSAttrs[sort.SearchInts(HiddenIndices, eidIndex)], HRand, curve.NewZrFromBytes(sig.EidNym.ProofSEid)) EidNym, err := t.G1FromProto(sig.EidNym.Nym) if err != nil { return err } - t4.Sub(EidNym.Mul(ProofC)) + t4_eid.Sub(EidNym.Mul(ProofC)) } + var t4_rh *math.G1 + if verifyRHNym { + H_a_rh, err := t.G1FromProto(ipk.HAttrs[rhIndex]) + if err != nil { + return err + } + t4_rh = H_a_rh.Mul2(ProofSAttrs[sort.SearchInts(HiddenIndices, rhIndex)], HRand, curve.NewZrFromBytes(sig.RhNym.ProofSRh)) + RhNym, err := t.G1FromProto(sig.RhNym.Nym) + if err != nil { + return err + } + t4_rh.Sub(RhNym.Mul(ProofC)) + } // add contribution from the non-revocation proof nonRevokedVer, err := getNonRevocationVerifier(RevocationAlgorithm(sig.NonRevocationProof.RevocationAlg)) if err != nil { @@ -777,7 +1013,6 @@ func (sig *Signature) Ver( if err != nil { return err } - // Recompute challenge // proofData is the data being hashed, it consists of: // the signature label @@ -785,13 +1020,20 @@ func (sig *Signature) Ver( // one bigint (hash of the issuer public key) of length math.FieldBytes // disclosed attributes // message that was signed - pdl := len([]byte(signLabel)) + 7*(2*curve.FieldBytes+1) + curve.FieldBytes + len(Disclosure) + len(msg) + ProofBytes[RevocationAlgorithm(sig.NonRevocationProof.RevocationAlg)] - if verifyEIDNym { - pdl = len([]byte(signWithEidNymLabel)) + 9*(2*curve.FieldBytes+1) + curve.FieldBytes + len(Disclosure) + len(msg) + ProofBytes[RevocationAlgorithm(sig.NonRevocationProof.RevocationAlg)] + // pdl is minimum length of proof data + pdl := curve.ScalarByteSize + len(Disclosure) + len(msg) + ProofBytes[RevocationAlgorithm(sig.NonRevocationProof.RevocationAlg)] + if verifyRHNym { // additional length for both an enrollment id and revocation handle attribute + pdl += len([]byte(signWithEidNymRhNymLabel)) + 11*curve.G1ByteSize + } else if verifyEIDNym { // additional length for an enrollment id attribute + pdl += len([]byte(signWithEidNymLabel)) + 9*curve.G1ByteSize + } else { // additional length for a standard sign label + pdl += len([]byte(signLabel)) + 7*curve.G1ByteSize } proofData := make([]byte, pdl) index := 0 - if verifyEIDNym { + if verifyRHNym { + index = appendBytesString(proofData, index, signWithEidNymRhNymLabel) + } else if verifyEIDNym { index = appendBytesString(proofData, index, signWithEidNymLabel) } else { index = appendBytesString(proofData, index, signLabel) @@ -804,42 +1046,98 @@ func (sig *Signature) Ver( index = appendBytesG1(proofData, index, BPrime) index = appendBytesG1(proofData, index, Nym) if verifyEIDNym { - Nym, err := t.G1FromProto(sig.EidNym.Nym) + EidNym, err := t.G1FromProto(sig.EidNym.Nym) if err != nil { return err } - - index = appendBytesG1(proofData, index, Nym) - index = appendBytesG1(proofData, index, t4) + index = appendBytesG1(proofData, index, EidNym) + index = appendBytesG1(proofData, index, t4_eid) + } + if verifyRHNym { + RhNym, err := t.G1FromProto(sig.RhNym.Nym) + if err != nil { + return err + } + index = appendBytesG1(proofData, index, RhNym) + index = appendBytesG1(proofData, index, t4_rh) } index = appendBytes(proofData, index, nonRevokedProofBytes) copy(proofData[index:], ipk.Hash) - index = index + curve.FieldBytes + index = index + curve.ScalarByteSize copy(proofData[index:], Disclosure) index = index + len(Disclosure) copy(proofData[index:], msg) c := curve.HashToZr(proofData) index = 0 - proofData = proofData[:2*curve.FieldBytes] + proofData = proofData[:2*curve.ScalarByteSize] index = appendBytesBig(proofData, index, c) appendBytesBig(proofData, index, Nonce) // audit eid nym if data provided and verification requested - if verifyEIDNym && meta != nil && meta.NymEIDAuditData != nil { - H_a_eid, err := t.G1FromProto(ipk.HAttrs[eidIndex]) + if (verifyEIDNym || verifyRHNym) && meta != nil { + EidNym, err := t.G1FromProto(sig.EidNym.Nym) if err != nil { return err } - EidNym, err := t.G1FromProto(sig.EidNym.Nym) + if meta.EidNymAuditData != nil { + H_a_eid, err := t.G1FromProto(ipk.HAttrs[eidIndex]) + if err != nil { + return err + } + + Nym_eid := H_a_eid.Mul2(meta.EidNymAuditData.Attr, HRand, meta.EidNymAuditData.Rand) + if !Nym_eid.Equals(EidNym) { + return errors.Errorf("signature invalid: nym eid validation failed, does not match regenerated nym eid") + } + + if meta.EidNymAuditData.Nym != nil && !EidNym.Equals(meta.EidNymAuditData.Nym) { + return errors.Errorf("signature invalid: nym eid validation failed, does not match metadata") + } + } + + if len(meta.EidNym) != 0 { + NymEID, err := curve.NewG1FromBytes(meta.EidNym) + if err != nil { + return errors.Errorf("signature invalid: nym eid validation failed, failed to unmarshal meta nym eid") + } + if !NymEID.Equals(EidNym) { + return errors.Errorf("signature invalid: nym eid validation failed, signature nym eid does not match metadata") + } + } + } + // audit rh nym if data provided and verification requested + if verifyRHNym && meta != nil { + RhNym, err := t.G1FromProto(sig.RhNym.Nym) if err != nil { return err } - Nym_eid := H_a_eid.Mul2(meta.NymEIDAuditData.EID, HRand, meta.NymEIDAuditData.RNymEid) - if !Nym_eid.Equals(EidNym) { - return errors.Errorf("signature invalid: nym eid validation failed") + if meta.RhNymAuditData != nil { + H_a_rh, err := t.G1FromProto(ipk.HAttrs[rhIndex]) + if err != nil { + return err + } + + Nym_rh := H_a_rh.Mul2(meta.RhNymAuditData.Attr, HRand, meta.RhNymAuditData.Rand) + if !Nym_rh.Equals(RhNym) { + return errors.Errorf("signature invalid: nym rh validation failed, does not match regenerated nym rh") + } + + if meta.RhNymAuditData.Nym != nil && !RhNym.Equals(meta.RhNymAuditData.Nym) { + return errors.Errorf("signature invalid: nym rh validation failed, does not match metadata") + } + } + + if len(meta.RhNym) != 0 { + NymRH, err := curve.NewG1FromBytes(meta.RhNym) + if err != nil { + return errors.Errorf("signature invalid: nym rh validation failed, failed to unmarshal meta nym rh") + } + if !NymRH.Equals(RhNym) { + return errors.Errorf("signature invalid: nym rh validation failed, signature nym rh does not match metadata") + } } } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/amcl.pb.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/amcl.pb.go index 2a7a385ca82..40be35751b5 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/amcl.pb.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/amcl.pb.go @@ -144,7 +144,7 @@ func init() { } var fileDescriptor_250ddfa5c5f8dbbb = []byte{ - // 185 bytes of a gzipped FileDescriptorProto + // 239 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x49, 0x4a, 0x4e, 0x2e, 0x2e, 0xd0, 0x2f, 0x4e, 0xce, 0x48, 0xcd, 0x4d, 0x2d, 0xd6, 0x4f, 0xc9, 0xc9, 0x4f, 0xd7, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0xd7, 0x2f, 0x29, 0x4a, 0xcc, 0x2b, 0xce, 0x49, 0x2c, 0xc9, 0x2f, @@ -153,8 +153,11 @@ var fileDescriptor_250ddfa5c5f8dbbb = []byte{ 0xa3, 0x06, 0x4f, 0x10, 0x63, 0x05, 0x88, 0x57, 0x29, 0xc1, 0x04, 0xe1, 0x55, 0x2a, 0xb9, 0x71, 0xb1, 0xb8, 0x3a, 0x07, 0x18, 0x09, 0xf1, 0x71, 0x31, 0x55, 0x24, 0x42, 0x15, 0x31, 0x55, 0x24, 0x82, 0xf9, 0x49, 0x50, 0x65, 0x4c, 0x15, 0x49, 0x20, 0x7e, 0x65, 0xa2, 0x04, 0x33, 0x84, 0x5f, - 0x09, 0x96, 0xaf, 0x4c, 0x92, 0x60, 0x81, 0xf2, 0x93, 0x9c, 0x1c, 0xa3, 0xec, 0xd3, 0x33, 0x4b, - 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x3d, 0x9d, 0x7c, 0xf5, 0x33, 0x53, 0x52, 0x73, - 0x33, 0x2b, 0xf4, 0x89, 0x76, 0x7e, 0x12, 0x1b, 0xd8, 0xe9, 0xc6, 0x80, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xae, 0x4d, 0xeb, 0xe4, 0xf2, 0x00, 0x00, 0x00, + 0x09, 0x96, 0xaf, 0x4c, 0x92, 0x60, 0x81, 0xf2, 0x93, 0x9c, 0xda, 0x18, 0xb9, 0x38, 0x92, 0xf3, + 0x73, 0xf5, 0x40, 0xf6, 0x3a, 0x71, 0x3a, 0xe6, 0x26, 0xe7, 0x04, 0x80, 0x1c, 0x12, 0xc0, 0x18, + 0x65, 0x9f, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0xef, 0xe9, 0xe4, 0xab, + 0x9f, 0x99, 0x92, 0x9a, 0x9b, 0x59, 0xa1, 0x4f, 0xb4, 0xb7, 0x16, 0x31, 0x31, 0x3b, 0x46, 0x44, + 0xac, 0x62, 0x62, 0x01, 0x19, 0x7a, 0x0a, 0x42, 0x3d, 0x62, 0x12, 0x00, 0x51, 0x31, 0xee, 0x01, + 0x4e, 0xbe, 0xa9, 0x25, 0x89, 0x29, 0x89, 0x25, 0x89, 0xaf, 0x20, 0x32, 0x49, 0x6c, 0xe0, 0x00, + 0x30, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x42, 0x17, 0x88, 0x52, 0x38, 0x01, 0x00, 0x00, } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/fp256bn.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/fp256bn.go index 6ba11b6590d..6d0320b8092 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/fp256bn.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl/fp256bn.go @@ -43,7 +43,7 @@ func (a *Fp256bn) G1FromProto(e *ECP) (*math.G1, error) { return nil, fmt.Errorf("nil argument") } - if len(e.X) != a.C.FieldBytes || len(e.Y) != a.C.FieldBytes { + if len(e.X) != a.C.CoordByteSize || len(e.Y) != a.C.CoordByteSize { return nil, fmt.Errorf("invalid marshalled length") } @@ -76,7 +76,7 @@ func (a *Fp256bn) G2FromProto(e *ECP2) (*math.G2, error) { return nil, fmt.Errorf("nil argument") } - if len(e.Xa) != a.C.FieldBytes || len(e.Xb) != a.C.FieldBytes || len(e.Ya) != a.C.FieldBytes || len(e.Yb) != a.C.FieldBytes { + if len(e.Xa) != a.C.CoordByteSize || len(e.Xb) != a.C.CoordByteSize || len(e.Ya) != a.C.CoordByteSize || len(e.Yb) != a.C.CoordByteSize { return nil, fmt.Errorf("invalid marshalled length") } @@ -120,7 +120,7 @@ func (a *Fp256bnMiracl) G1FromProto(e *ECP) (*math.G1, error) { return nil, fmt.Errorf("nil argument") } - if len(e.X) != a.C.FieldBytes || len(e.Y) != a.C.FieldBytes { + if len(e.X) != a.C.CoordByteSize || len(e.Y) != a.C.CoordByteSize { return nil, fmt.Errorf("invalid marshalled length") } @@ -153,7 +153,7 @@ func (a *Fp256bnMiracl) G2FromProto(e *ECP2) (*math.G2, error) { return nil, fmt.Errorf("nil argument") } - if len(e.Xa) != a.C.FieldBytes || len(e.Xb) != a.C.FieldBytes || len(e.Ya) != a.C.FieldBytes || len(e.Yb) != a.C.FieldBytes { + if len(e.Xa) != a.C.CoordByteSize || len(e.Xb) != a.C.CoordByteSize || len(e.Ya) != a.C.CoordByteSize || len(e.Yb) != a.C.CoordByteSize { return nil, fmt.Errorf("invalid marshalled length") } diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/util.go b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/util.go index 6edeaabe337..fe95016f181 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/util.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/util.go @@ -58,10 +58,10 @@ func (i *Idemix) MakeNymFromBytes(raw []byte) (*math.G1, *math.Zr, error) { } func makeNymFromBytes(curve *math.Curve, raw []byte, translator Translator) (*math.G1, *math.Zr, error) { - RandNym := curve.NewZrFromBytes(raw[:curve.FieldBytes]) + RandNym := curve.NewZrFromBytes(raw[:curve.ScalarByteSize]) pk, err := translator.G1FromProto(&amcl.ECP{ - X: raw[curve.FieldBytes : 2*curve.FieldBytes], - Y: raw[2*curve.FieldBytes:], + X: raw[curve.ScalarByteSize : curve.ScalarByteSize+curve.CoordByteSize], + Y: raw[curve.ScalarByteSize+curve.CoordByteSize:], }) if err != nil { return nil, nil, err diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/weak-bb/LICENSE b/vendor/github.com/IBM/idemix/bccsp/schemes/weak-bb/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/weak-bb/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/weak-bb.go b/vendor/github.com/IBM/idemix/bccsp/schemes/weak-bb/weak-bb.go similarity index 70% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/weak-bb.go rename to vendor/github.com/IBM/idemix/bccsp/schemes/weak-bb/weak-bb.go index a228ae67433..8668e469606 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/crypto/weak-bb.go +++ b/vendor/github.com/IBM/idemix/bccsp/schemes/weak-bb/weak-bb.go @@ -4,7 +4,7 @@ Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package idemix +package weakbb import ( "io" @@ -13,8 +13,8 @@ import ( "github.com/pkg/errors" ) -// wbbKeyGen creates a fresh weak-Boneh-Boyen signature key pair (http://ia.cr/2004/171) -func wbbKeyGen(curve *math.Curve, rng io.Reader) (*math.Zr, *math.G2) { +// WbbKeyGen creates a fresh weak-Boneh-Boyen signature key pair (http://ia.cr/2004/171) +func WbbKeyGen(curve *math.Curve, rng io.Reader) (*math.Zr, *math.G2) { // sample sk uniform from Zq sk := curve.NewRandomZr(rng) // set pk = g2^sk @@ -22,8 +22,8 @@ func wbbKeyGen(curve *math.Curve, rng io.Reader) (*math.Zr, *math.G2) { return sk, pk } -// wbbSign places a weak Boneh-Boyen signature on message m using secret key sk -func wbbSign(curve *math.Curve, sk *math.Zr, m *math.Zr) *math.G1 { +// WbbSign places a weak Boneh-Boyen signature on message m using secret key sk +func WbbSign(curve *math.Curve, sk *math.Zr, m *math.Zr) *math.G1 { // compute exp = 1/(m + sk) mod q exp := curve.ModAdd(sk, m, curve.GroupOrder) exp.InvModP(curve.GroupOrder) @@ -32,8 +32,8 @@ func wbbSign(curve *math.Curve, sk *math.Zr, m *math.Zr) *math.G1 { return curve.GenG1.Mul(exp) } -// wbbVerify verifies a weak Boneh-Boyen signature sig on message m with public key pk -func wbbVerify(curve *math.Curve, pk *math.G2, sig *math.G1, m *math.Zr) error { +// WbbVerify verifies a weak Boneh-Boyen signature sig on message m with public key pk +func WbbVerify(curve *math.Curve, pk *math.G2, sig *math.G1, m *math.Zr) error { if pk == nil || sig == nil || m == nil { return errors.Errorf("Weak-BB signature invalid: received nil input") } diff --git a/vendor/github.com/IBM/idemix/bccsp/types/LICENSE b/vendor/github.com/IBM/idemix/bccsp/types/LICENSE new file mode 100644 index 00000000000..261eeb9e9f8 --- /dev/null +++ b/vendor/github.com/IBM/idemix/bccsp/types/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/crypto.go b/vendor/github.com/IBM/idemix/bccsp/types/crypto.go similarity index 99% rename from vendor/github.com/IBM/idemix/bccsp/schemes/crypto.go rename to vendor/github.com/IBM/idemix/bccsp/types/crypto.go index e4cfa52a31a..aa3dffd0291 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/crypto.go +++ b/vendor/github.com/IBM/idemix/bccsp/types/crypto.go @@ -3,7 +3,7 @@ Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package idemix +package types import ( "crypto" diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/idemix.go b/vendor/github.com/IBM/idemix/bccsp/types/idemix.go similarity index 81% rename from vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/idemix.go rename to vendor/github.com/IBM/idemix/bccsp/types/idemix.go index fea7d2b9956..a44c74a922f 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/dlog/handlers/idemix.go +++ b/vendor/github.com/IBM/idemix/bccsp/types/idemix.go @@ -3,12 +3,11 @@ Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package handlers +package types import ( "crypto/ecdsa" - bccsp "github.com/IBM/idemix/bccsp/schemes" math "github.com/IBM/mathlib" ) @@ -47,18 +46,6 @@ type Issuer interface { NewPublicKeyFromBytes(raw []byte, attributes []string) (IssuerPublicKey, error) } -// Big represent a big integer -type Big interface { - // Bytes returns the byte representation of this key - Bytes() []byte -} - -// Ecp represents an elliptic curve point -type Ecp interface { - // Bytes returns the byte representation of this key - Bytes() []byte -} - // User is a local interface to decouple from the idemix implementation type User interface { // NewKey generates a new User secret key @@ -87,6 +74,20 @@ type CredRequest interface { Verify(credRequest []byte, ipk IssuerPublicKey, nonce []byte) error } +// BlindCredRequest is similar to CredRequest except it provides a hiding +// commitment to the hidden attribute (the user secret key), and so it +// requires an additional `Unblind` function to account for the randomness +type BlindCredRequest interface { + // Blind creates a request to sign the value sk + Blind(sk *math.Zr, ipk IssuerPublicKey, nonce []byte) ([]byte, []byte, error) + + // Verify verifies the credential request + BlindVerify(credRequest []byte, ipk IssuerPublicKey, nonce []byte) error + + // Unblind takes a blinded signature and a blinding and produces a standard signature + Unblind(signature, blinding []byte) ([]byte, error) +} + // CredRequest is a local interface to decouple from the idemix implementation // of the issuance of credentials. type Credential interface { @@ -94,11 +95,11 @@ type Credential interface { // Sign issues a new credential, which is the last step of the interactive issuance protocol // All attribute values are added by the issuer at this step and then signed together with a commitment to // the user's secret key from a credential request - Sign(key IssuerSecretKey, credentialRequest []byte, attributes []bccsp.IdemixAttribute) ([]byte, error) + Sign(key IssuerSecretKey, credentialRequest []byte, attributes []IdemixAttribute) ([]byte, error) // Verify cryptographically verifies the credential by verifying the signature // on the attribute values and user's secret key - Verify(sk *math.Zr, ipk IssuerPublicKey, credential []byte, attributes []bccsp.IdemixAttribute) error + Verify(sk *math.Zr, ipk IssuerPublicKey, credential []byte, attributes []IdemixAttribute) error } // Revocation is a local interface to decouple from the idemix implementation @@ -115,14 +116,14 @@ type Revocation interface { // Users can use the CRI to prove that they are not revoked. // Note that when not using revocation (i.e., alg = ALG_NO_REVOCATION), the entered unrevokedHandles are not used, // and the resulting CRI can be used by any signer. - Sign(key *ecdsa.PrivateKey, unrevokedHandles [][]byte, epoch int, alg bccsp.RevocationAlgorithm) ([]byte, error) + Sign(key *ecdsa.PrivateKey, unrevokedHandles [][]byte, epoch int, alg RevocationAlgorithm) ([]byte, error) // Verify verifies that the revocation PK for a certain epoch is valid, // by checking that it was signed with the long term revocation key. // Note that even if we use no revocation (i.e., alg = ALG_NO_REVOCATION), we need // to verify the signature to make sure the issuer indeed signed that no revocation // is used in this epoch. - Verify(pk *ecdsa.PublicKey, cri []byte, epoch int, alg bccsp.RevocationAlgorithm) error + Verify(pk *ecdsa.PublicKey, cri []byte, epoch int, alg RevocationAlgorithm) error } // SignatureScheme is a local interface to decouple from the idemix implementation @@ -142,8 +143,7 @@ type SignatureScheme interface { // rhIndex: revocation handle index relative to attributes; // cri: the serialized version of the Credential Revocation Information (it contains the epoch this signature // is created in reference to). - Sign(cred []byte, sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk IssuerPublicKey, attributes []bccsp.IdemixAttribute, - msg []byte, rhIndex, eidIndex int, cri []byte, sigType bccsp.SignatureType) ([]byte, *bccsp.IdemixSignerMetadata, error) + Sign(cred []byte, sk *math.Zr, Nym *math.G1, RNym *math.Zr, ipk IssuerPublicKey, attributes []IdemixAttribute, msg []byte, rhIndex, eidIndex int, cri []byte, sigType SignatureType, metadata *IdemixSignerMetadata) ([]byte, *IdemixSignerMetadata, error) // Verify verifies an idemix signature. // The attribute slice steers which attributes it expects to be disclosed @@ -158,12 +158,14 @@ type SignatureScheme interface { // rhIndex: revocation handle index relative to attributes; // revocationPublicKey: revocation public key; // epoch: revocation epoch. - Verify(ipk IssuerPublicKey, signature, msg []byte, attributes []bccsp.IdemixAttribute, rhIndex, eidIndex int, - revocationPublicKey *ecdsa.PublicKey, epoch int, verType bccsp.VerificationType, meta *bccsp.IdemixSignerMetadata) error + Verify(ipk IssuerPublicKey, signature, msg []byte, attributes []IdemixAttribute, rhIndex, eidIndex int, + revocationPublicKey *ecdsa.PublicKey, epoch int, verType VerificationType, meta *IdemixSignerMetadata) error // AuditNymEid permits the auditing of the nym eid generated by a signer - AuditNymEid(ipk IssuerPublicKey, eidIndex int, signature []byte, - enrollmentID string, RNymEid *math.Zr) error + AuditNymEid(ipk IssuerPublicKey, eidIndex int, signature []byte, enrollmentID string, RNymEid *math.Zr, verType AuditVerificationType) error + + // AuditNymRh permits the auditing of the nym rh generated by a signer + AuditNymRh(ipk IssuerPublicKey, rhIndex int, signature []byte, revocationHandle string, RNymRh *math.Zr, verType AuditVerificationType) error } // NymSignatureScheme is a local interface to decouple from the idemix implementation diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/idemixerrs.go b/vendor/github.com/IBM/idemix/bccsp/types/idemixerrs.go similarity index 98% rename from vendor/github.com/IBM/idemix/bccsp/schemes/idemixerrs.go rename to vendor/github.com/IBM/idemix/bccsp/types/idemixerrs.go index 99c620e1896..d0d3f64fc11 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/idemixerrs.go +++ b/vendor/github.com/IBM/idemix/bccsp/types/idemixerrs.go @@ -4,7 +4,7 @@ Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package idemix +package types import ( "fmt" diff --git a/vendor/github.com/IBM/idemix/bccsp/schemes/idemixopts.go b/vendor/github.com/IBM/idemix/bccsp/types/idemixopts.go similarity index 79% rename from vendor/github.com/IBM/idemix/bccsp/schemes/idemixopts.go rename to vendor/github.com/IBM/idemix/bccsp/types/idemixopts.go index fe1e2deeb93..393f3262e70 100644 --- a/vendor/github.com/IBM/idemix/bccsp/schemes/idemixopts.go +++ b/vendor/github.com/IBM/idemix/bccsp/types/idemixopts.go @@ -3,7 +3,7 @@ Copyright IBM Corp. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ -package idemix +package types import ( "crypto" @@ -190,6 +190,27 @@ func (o *IdemixCredentialRequestSignerOpts) HashFunc() crypto.Hash { return o.H } +// IdemixCredentialRequestSignerOpts contains the option to create a Idemix credential request. +type IdemixBlindCredentialRequestSignerOpts struct { + // Attributes contains a list of indices of the attributes to be included in the + // credential. The indices are with the respect to IdemixIssuerKeyGenOpts#AttributeNames. + Attributes []int + // IssuerPK is the public-key of the issuer + IssuerPK Key + // IssuerNonce is generated by the issuer and used by the client to generate the credential request. + // Once the issuer gets the credential requests, it checks that the nonce is the same. + IssuerNonce []byte + // HashFun is the hash function to be used + H crypto.Hash + + // Blinding contains the blinding used to mask the unrevealed attributes + Blinding []byte +} + +func (o *IdemixBlindCredentialRequestSignerOpts) HashFunc() crypto.Hash { + return o.H +} + // IssuerPublicKey returns the issuer public key used to derive // a new unlinkable pseudonym from a credential secret key func (o *IdemixCredentialRequestSignerOpts) IssuerPublicKey() Key { @@ -236,16 +257,25 @@ func (o *IdemixCredentialSignerOpts) IssuerPublicKey() Key { return o.IssuerPK } -type NymEIDAuditData struct { - // RNymEid is the randomness used to generate the EID Nym - RNymEid *math.Zr +// AttrNymAuditData contains the data that is used to audit a commitment to an auditable attribute. +// Nym is a commitment to the Attr. Attr can be an Enrollment ID or a Revocation Handle. +// Notice that this data should be used only after validating the corresponding signature. +type AttrNymAuditData struct { + // Nym is the commitment to an attribute + Nym *math.G1 + + // RAttrNym is the randomness used to generate the Attr Nym + Rand *math.Zr - // EID is the enrollment id - EID *math.Zr + // Attr is the attribute (enrollment id or revocation handle) + Attr *math.Zr } type IdemixSignerMetadata struct { - NymEIDAuditData *NymEIDAuditData + EidNym []byte + EidNymAuditData *AttrNymAuditData + RhNym []byte + RhNymAuditData *AttrNymAuditData } // IdemixSignerOpts contains the options to generate an Idemix signature @@ -264,7 +294,7 @@ type IdemixSignerOpts struct { // then Attributes[i].Value must be set accordingly. Attributes []IdemixAttribute // RhIndex is the index of attribute containing the revocation handler. - // Notice that this attributed cannot be discloused + // Notice that this attributed cannot be disclosed RhIndex int // EidIndex contains the index of the EID attrbiute EidIndex int @@ -288,16 +318,30 @@ func (o *IdemixSignerOpts) HashFunc() crypto.Hash { return o.H } +// EidNymAuditOpts contains audit options for pseudonymous enrollment id type EidNymAuditOpts struct { - EidIndex int - EnrollmentID string - RNymEid *math.Zr + AuditVerificationType AuditVerificationType + EidIndex int // Index of enrollment ID attribute in signature + EnrollmentID string // Enrollment ID of identity + RNymEid *math.Zr // Field element of randomness } func (o *EidNymAuditOpts) HashFunc() crypto.Hash { return 0 } +// RhNymAuditOpts contains audit options for pseudonymous revocation handle +type RhNymAuditOpts struct { + AuditVerificationType AuditVerificationType + RhIndex int // Index of revocation handle attribute in signature + RevocationHandle string // Revocation handle of identity + RNymRh *math.Zr // Field element of randomness +} + +func (o *RhNymAuditOpts) HashFunc() crypto.Hash { + return 0 +} + // IdemixNymSignerOpts contains the options to generate an idemix pseudonym signature. type IdemixNymSignerOpts struct { // Nym is the pseudonym to be used @@ -387,13 +431,15 @@ const ( Standard SignatureType = iota // EidNym adds a hiding and binding commitment to the enrollment id and proves its correctness EidNym + // EidNymRhNym adds a hiding and binding commitment to both the enrollment id and the revocation handle and proves each of their correctness + EidNymRhNym ) // VerificationType describes the type of verification that is required type VerificationType int const ( - // Basic performs the verification without any of the extensions (e.g. it ignores the nym eid) + // Basic performs the verification without any of the extensions (e.g. it ignores the eid nym and rh nym) Basic VerificationType = iota // BestEffort performs all verifications possible given the available information in the signature/opts BestEffort @@ -401,4 +447,18 @@ const ( ExpectStandard // ExpectEidNym expects a SignatureType of type EidNym ExpectEidNym + // ExpectEidNymRhNym expects a SignatureType of EidNymRhNym + ExpectEidNymRhNym +) + +// AuditVerificationType describes the type of audit verification that is required +type AuditVerificationType int + +const ( + // AuditExpectSignature performs the audit verification against a signature + AuditExpectSignature AuditVerificationType = iota + // AuditExpectEidNym performs the audit verification against an EID pseudonym + AuditExpectEidNym + // AuditExpectEidNymRhNym performs the audit verification against an EID pseudonym and a Revocation Handle pseudonym + AuditExpectEidNymRhNym ) diff --git a/vendor/github.com/IBM/idemix/buf.gen.yaml b/vendor/github.com/IBM/idemix/buf.gen.yaml new file mode 100644 index 00000000000..65d1127d88e --- /dev/null +++ b/vendor/github.com/IBM/idemix/buf.gen.yaml @@ -0,0 +1,7 @@ +version: v1 +managed: + enabled: true +plugins: + - name: go + out: . + opt: paths=source_relative diff --git a/vendor/github.com/IBM/idemix/common/flogging/fabenc/formatter.go b/vendor/github.com/IBM/idemix/common/flogging/fabenc/formatter.go index 6d6c5a8baa7..b2101e5db83 100644 --- a/vendor/github.com/IBM/idemix/common/flogging/fabenc/formatter.go +++ b/vendor/github.com/IBM/idemix/common/flogging/fabenc/formatter.go @@ -19,9 +19,9 @@ import ( ) // formatRegexp is broken into three groups: -// 1. the format verb -// 2. an optional colon that is ungrouped with '?:' -// 3. an optional, non-greedy format directive +// 1. the format verb +// 2. an optional colon that is ungrouped with '?:' +// 3. an optional, non-greedy format directive // // The grouping simplifies the verb proccssing during spec parsing. var formatRegexp = regexp.MustCompile(`%{(color|id|level|message|module|shortfunc|time)(?::(.*?))?}`) @@ -44,7 +44,6 @@ var formatRegexp = regexp.MustCompile(`%{(color|id|level|message|module|shortfun // - level: a fmt style string formatter without the leading % // - message: a fmt style string formatter without the leading % // - module: a fmt style string formatter without the leading % -// func ParseFormat(spec string) ([]Formatter, error) { cursor := 0 formatters := []Formatter{} diff --git a/vendor/github.com/IBM/idemix/common/flogging/loggerlevels.go b/vendor/github.com/IBM/idemix/common/flogging/loggerlevels.go index 8af426f81eb..d306e624d5d 100644 --- a/vendor/github.com/IBM/idemix/common/flogging/loggerlevels.go +++ b/vendor/github.com/IBM/idemix/common/flogging/loggerlevels.go @@ -38,7 +38,8 @@ func (l *LoggerLevels) DefaultLevel() zapcore.Level { // ActivateSpec is used to modify logging levels. // // The logging specification has the following form: -// [[,...]=][:[[,...]=]...] +// +// [[,...]=][:[[,...]=]...] func (l *LoggerLevels) ActivateSpec(spec string) error { l.mutex.Lock() defer l.mutex.Unlock() diff --git a/vendor/github.com/IBM/idemix/idemixmsp.go b/vendor/github.com/IBM/idemix/idemixmsp.go index 213bc6ad31c..34542451208 100644 --- a/vendor/github.com/IBM/idemix/idemixmsp.go +++ b/vendor/github.com/IBM/idemix/idemixmsp.go @@ -16,12 +16,12 @@ import ( idemix "github.com/IBM/idemix/bccsp" "github.com/IBM/idemix/bccsp/keystore" - bccsp "github.com/IBM/idemix/bccsp/schemes" "github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl" + bccsp "github.com/IBM/idemix/bccsp/types" "github.com/IBM/idemix/common/flogging" + im "github.com/IBM/idemix/idemixmsp" math "github.com/IBM/mathlib" "github.com/golang/protobuf/proto" - "github.com/hyperledger/fabric-protos-go/msp" m "github.com/hyperledger/fabric-protos-go/msp" "github.com/pkg/errors" "go.uber.org/zap/zapcore" @@ -96,6 +96,21 @@ func NewIdemixMsp(version MSPVersion) (MSP, error) { return &msp, nil } +// NewIdemixMspAries creates a new instance of idemixmsp +func NewIdemixMspAries(version MSPVersion) (MSP, error) { + mspLogger.Debugf("Creating Idemix-based MSP instance") + + curve := math.Curves[math.BLS12_381_BBS] + csp, err := idemix.NewAries(&keystore.Dummy{}, curve, &amcl.Gurvy{C: curve}, true) + if err != nil { + panic(fmt.Sprintf("unexpected condition, error received [%s]", err)) + } + + msp := Idemixmsp{csp: csp} + msp.version = version + return &msp, nil +} + func (msp *Idemixmsp) Setup(conf1 *m.MSPConfig) error { mspLogger.Debugf("Setting up Idemix-based MSP instance") @@ -103,11 +118,7 @@ func (msp *Idemixmsp) Setup(conf1 *m.MSPConfig) error { return errors.Errorf("setup error: nil conf reference") } - if conf1.Type != int32(IDEMIX) { - return errors.Errorf("setup error: config is not of type IDEMIX") - } - - var conf m.IdemixMSPConfig + var conf im.IdemixMSPConfig err := proto.Unmarshal(conf1.Config, &conf) if err != nil { return errors.Wrap(err, "failed unmarshalling idemix msp config") @@ -116,6 +127,13 @@ func (msp *Idemixmsp) Setup(conf1 *m.MSPConfig) error { msp.name = conf.Name mspLogger.Debugf("Setting up Idemix MSP instance %s", msp.name) + switch conf1.Type { + case int32(IDEMIX): + case int32(IDEMIX_ARIES): + default: + return errors.Errorf("setup error: config is not of type IDEMIX") + } + // Import Issuer Public Key IssuerPublicKey, err := msp.csp.KeyImport( conf.Ipk, @@ -291,7 +309,7 @@ func (msp *Idemixmsp) DeserializeIdentity(serializedID []byte) (Identity, error) func (msp *Idemixmsp) DeserializeIdentityInternal(serializedID []byte) (Identity, error) { mspLogger.Debug("idemixmsp: deserializing identity") - serialized := new(m.SerializedIdemixIdentity) + serialized := new(im.SerializedIdemixIdentity) err := proto.Unmarshal(serializedID, serialized) if err != nil { return nil, errors.Wrap(err, "could not deserialize a SerializedIdemixIdentity") @@ -515,7 +533,7 @@ func (msp *Idemixmsp) satisfiesPrincipalValidated(id Identity, principal *m.MSPP // In this MSP implementation, an identity is considered well formed if it contains a // marshaled SerializedIdemixIdentity protobuf message. func (id *Idemixmsp) IsWellFormed(identity *m.SerializedIdentity) error { - sId := new(m.SerializedIdemixIdentity) + sId := new(im.SerializedIdemixIdentity) err := proto.Unmarshal(identity.IdBytes, sId) if err != nil { return errors.Wrap(err, "not an idemix identity") @@ -621,7 +639,7 @@ func (id *Idemixidentity) SatisfiesPrincipal(principal *m.MSPPrincipal) error { } func (id *Idemixidentity) Serialize() ([]byte, error) { - serialized := &m.SerializedIdemixIdentity{} + serialized := &im.SerializedIdemixIdentity{} raw, err := id.NymPublicKey.Bytes() if err != nil { @@ -706,7 +724,12 @@ const ( ) // GetIdemixMspConfig returns the configuration for the Idemix MSP -func GetIdemixMspConfig(dir string, ID string) (*msp.MSPConfig, error) { +func GetIdemixMspConfig(dir string, ID string) (*m.MSPConfig, error) { + return GetIdemixMspConfigWithType(dir, ID, IDEMIX) +} + +// GetIdemixMspConfigWithType returns the configuration for the Idemix MSP of the specified type +func GetIdemixMspConfigWithType(dir string, ID string, mspType ProviderType) (*m.MSPConfig, error) { ipkBytes, err := readFile(filepath.Join(dir, IdemixConfigDirMsp, IdemixConfigFileIssuerPublicKey)) if err != nil { return nil, errors.Wrapf(err, "failed to read issuer public key file") @@ -717,7 +740,7 @@ func GetIdemixMspConfig(dir string, ID string) (*msp.MSPConfig, error) { return nil, errors.Wrapf(err, "failed to read revocation public key file") } - idemixConfig := &msp.IdemixMSPConfig{ + idemixConfig := &im.IdemixMSPConfig{ Name: ID, Ipk: ipkBytes, RevocationPk: revocationPkBytes, @@ -725,7 +748,7 @@ func GetIdemixMspConfig(dir string, ID string) (*msp.MSPConfig, error) { signerBytes, err := readFile(filepath.Join(dir, IdemixConfigDirUser, IdemixConfigFileSigner)) if err == nil { - signerConfig := &msp.IdemixMSPSignerConfig{} + signerConfig := &im.IdemixMSPSignerConfig{} err = proto.Unmarshal(signerBytes, signerConfig) if err != nil { return nil, err @@ -738,5 +761,5 @@ func GetIdemixMspConfig(dir string, ID string) (*msp.MSPConfig, error) { return nil, err } - return &msp.MSPConfig{Config: confBytes, Type: int32(IDEMIX)}, nil + return &m.MSPConfig{Config: confBytes, Type: int32(mspType)}, nil } diff --git a/vendor/github.com/IBM/idemix/idemixmsp/identities.pb.go b/vendor/github.com/IBM/idemix/idemixmsp/identities.pb.go new file mode 100644 index 00000000000..b45eca931e9 --- /dev/null +++ b/vendor/github.com/IBM/idemix/idemixmsp/identities.pb.go @@ -0,0 +1,130 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: idemixmsp/identities.proto + +package idemixmsp + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +// This struct represents an Idemix Identity +// to be used to serialize it and deserialize it. +// The IdemixMSP will first serialize an idemix identity to bytes using +// this proto, and then uses these bytes as id_bytes in SerializedIdentity +type SerializedIdemixIdentity struct { + // nym_x is the X-component of the pseudonym elliptic curve point. + // It is a []byte representation of an amcl.BIG + // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. + NymX []byte `protobuf:"bytes,1,opt,name=nym_x,json=nymX,proto3" json:"nym_x,omitempty"` + // nym_y is the Y-component of the pseudonym elliptic curve point. + // It is a []byte representation of an amcl.BIG + // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. + NymY []byte `protobuf:"bytes,2,opt,name=nym_y,json=nymY,proto3" json:"nym_y,omitempty"` + // ou contains the organizational unit of the idemix identity + Ou []byte `protobuf:"bytes,3,opt,name=ou,proto3" json:"ou,omitempty"` + // role contains the role of this identity (e.g., ADMIN or MEMBER) + Role []byte `protobuf:"bytes,4,opt,name=role,proto3" json:"role,omitempty"` + // proof contains the cryptographic evidence that this identity is valid + Proof []byte `protobuf:"bytes,5,opt,name=proof,proto3" json:"proof,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *SerializedIdemixIdentity) Reset() { *m = SerializedIdemixIdentity{} } +func (m *SerializedIdemixIdentity) String() string { return proto.CompactTextString(m) } +func (*SerializedIdemixIdentity) ProtoMessage() {} +func (*SerializedIdemixIdentity) Descriptor() ([]byte, []int) { + return fileDescriptor_cb8a4544fc71d2d8, []int{0} +} + +func (m *SerializedIdemixIdentity) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_SerializedIdemixIdentity.Unmarshal(m, b) +} +func (m *SerializedIdemixIdentity) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_SerializedIdemixIdentity.Marshal(b, m, deterministic) +} +func (m *SerializedIdemixIdentity) XXX_Merge(src proto.Message) { + xxx_messageInfo_SerializedIdemixIdentity.Merge(m, src) +} +func (m *SerializedIdemixIdentity) XXX_Size() int { + return xxx_messageInfo_SerializedIdemixIdentity.Size(m) +} +func (m *SerializedIdemixIdentity) XXX_DiscardUnknown() { + xxx_messageInfo_SerializedIdemixIdentity.DiscardUnknown(m) +} + +var xxx_messageInfo_SerializedIdemixIdentity proto.InternalMessageInfo + +func (m *SerializedIdemixIdentity) GetNymX() []byte { + if m != nil { + return m.NymX + } + return nil +} + +func (m *SerializedIdemixIdentity) GetNymY() []byte { + if m != nil { + return m.NymY + } + return nil +} + +func (m *SerializedIdemixIdentity) GetOu() []byte { + if m != nil { + return m.Ou + } + return nil +} + +func (m *SerializedIdemixIdentity) GetRole() []byte { + if m != nil { + return m.Role + } + return nil +} + +func (m *SerializedIdemixIdentity) GetProof() []byte { + if m != nil { + return m.Proof + } + return nil +} + +func init() { + proto.RegisterType((*SerializedIdemixIdentity)(nil), "idemixmsp.SerializedIdemixIdentity") +} + +func init() { proto.RegisterFile("idemixmsp/identities.proto", fileDescriptor_cb8a4544fc71d2d8) } + +var fileDescriptor_cb8a4544fc71d2d8 = []byte{ + // 231 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0xca, 0x4c, 0x49, 0xcd, + 0xcd, 0xac, 0xc8, 0x2d, 0x2e, 0xd0, 0xcf, 0x4c, 0x49, 0xcd, 0x2b, 0xc9, 0x2c, 0xc9, 0x4c, 0x2d, + 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x84, 0xcb, 0x29, 0xd5, 0x71, 0x49, 0x04, 0xa7, + 0x16, 0x65, 0x26, 0xe6, 0x64, 0x56, 0xa5, 0xa6, 0x78, 0x82, 0x85, 0x3d, 0x21, 0xca, 0x2b, 0x85, + 0x84, 0xb9, 0x58, 0xf3, 0x2a, 0x73, 0xe3, 0x2b, 0x24, 0x18, 0x15, 0x18, 0x35, 0x78, 0x82, 0x58, + 0xf2, 0x2a, 0x73, 0x23, 0x60, 0x82, 0x95, 0x12, 0x4c, 0x70, 0xc1, 0x48, 0x21, 0x3e, 0x2e, 0xa6, + 0xfc, 0x52, 0x09, 0x66, 0xb0, 0x08, 0x53, 0x7e, 0xa9, 0x90, 0x10, 0x17, 0x4b, 0x51, 0x7e, 0x4e, + 0xaa, 0x04, 0x0b, 0x44, 0x0d, 0x88, 0x2d, 0x24, 0xc2, 0xc5, 0x5a, 0x50, 0x94, 0x9f, 0x9f, 0x26, + 0xc1, 0x0a, 0x16, 0x84, 0x70, 0x9c, 0x5a, 0x19, 0xb9, 0x78, 0x93, 0xf3, 0x73, 0xf5, 0xe0, 0x2e, + 0x72, 0xe2, 0xf7, 0x84, 0x3b, 0x37, 0x00, 0xe4, 0xda, 0x00, 0xc6, 0x28, 0xf9, 0xf4, 0xcc, 0x92, + 0x8c, 0xd2, 0x24, 0xbd, 0xe4, 0xfc, 0x5c, 0x7d, 0x4f, 0x27, 0x5f, 0x7d, 0x88, 0x62, 0x7d, 0xb8, + 0x9e, 0x45, 0x4c, 0xcc, 0x9e, 0x11, 0x11, 0xab, 0x98, 0x38, 0x3d, 0x61, 0x22, 0xa7, 0x90, 0xd8, + 0x8f, 0x98, 0x44, 0xe1, 0xec, 0x18, 0xf7, 0x00, 0x27, 0xdf, 0xd4, 0x92, 0xc4, 0x94, 0xc4, 0x92, + 0xc4, 0x57, 0x48, 0x6a, 0x92, 0xd8, 0xc0, 0x21, 0x63, 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x6a, + 0xc5, 0x9b, 0x6e, 0x37, 0x01, 0x00, 0x00, +} diff --git a/vendor/github.com/IBM/idemix/idemixmsp/identities.proto b/vendor/github.com/IBM/idemix/idemixmsp/identities.proto new file mode 100644 index 00000000000..48e64faafc0 --- /dev/null +++ b/vendor/github.com/IBM/idemix/idemixmsp/identities.proto @@ -0,0 +1,35 @@ + +// Copyright the Hyperledger Fabric contributors. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; + +option go_package = "github.com/IBM/idemix/idemixmsp"; + +package idemixmsp; + +// This struct represents an Idemix Identity +// to be used to serialize it and deserialize it. +// The IdemixMSP will first serialize an idemix identity to bytes using +// this proto, and then uses these bytes as id_bytes in SerializedIdentity +message SerializedIdemixIdentity { + // nym_x is the X-component of the pseudonym elliptic curve point. + // It is a []byte representation of an amcl.BIG + // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. + bytes nym_x = 1; + + // nym_y is the Y-component of the pseudonym elliptic curve point. + // It is a []byte representation of an amcl.BIG + // The pseudonym can be seen as a public key of the identity, it is used to verify signatures. + bytes nym_y = 2; + + // ou contains the organizational unit of the idemix identity + bytes ou = 3; + + // role contains the role of this identity (e.g., ADMIN or MEMBER) + bytes role = 4; + + // proof contains the cryptographic evidence that this identity is valid + bytes proof = 5; +} \ No newline at end of file diff --git a/vendor/github.com/IBM/idemix/idemixmsp/msp_config.pb.go b/vendor/github.com/IBM/idemix/idemixmsp/msp_config.pb.go new file mode 100644 index 00000000000..d857d58fd97 --- /dev/null +++ b/vendor/github.com/IBM/idemix/idemixmsp/msp_config.pb.go @@ -0,0 +1,239 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: idemixmsp/msp_config.proto + +package idemixmsp + +import ( + fmt "fmt" + proto "github.com/golang/protobuf/proto" + math "math" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package + +type IdemixMSPConfig struct { + // Name holds the identifier of the MSP + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // ipk represents the (serialized) issuer public key + Ipk []byte `protobuf:"bytes,2,opt,name=ipk,proto3" json:"ipk,omitempty"` + // signer may contain crypto material to configure a default signer + Signer *IdemixMSPSignerConfig `protobuf:"bytes,3,opt,name=signer,proto3" json:"signer,omitempty"` + // revocation_pk is the public key used for revocation of credentials + RevocationPk []byte `protobuf:"bytes,4,opt,name=revocation_pk,json=revocationPk,proto3" json:"revocation_pk,omitempty"` + // epoch represents the current epoch (time interval) used for revocation + Epoch int64 `protobuf:"varint,5,opt,name=epoch,proto3" json:"epoch,omitempty"` + // curve_id indicates which Elliptic Curve should be used + CurveId string `protobuf:"bytes,6,opt,name=curve_id,json=curveId,proto3" json:"curve_id,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IdemixMSPConfig) Reset() { *m = IdemixMSPConfig{} } +func (m *IdemixMSPConfig) String() string { return proto.CompactTextString(m) } +func (*IdemixMSPConfig) ProtoMessage() {} +func (*IdemixMSPConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_783ba658a7862c73, []int{0} +} + +func (m *IdemixMSPConfig) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IdemixMSPConfig.Unmarshal(m, b) +} +func (m *IdemixMSPConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IdemixMSPConfig.Marshal(b, m, deterministic) +} +func (m *IdemixMSPConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_IdemixMSPConfig.Merge(m, src) +} +func (m *IdemixMSPConfig) XXX_Size() int { + return xxx_messageInfo_IdemixMSPConfig.Size(m) +} +func (m *IdemixMSPConfig) XXX_DiscardUnknown() { + xxx_messageInfo_IdemixMSPConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_IdemixMSPConfig proto.InternalMessageInfo + +func (m *IdemixMSPConfig) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *IdemixMSPConfig) GetIpk() []byte { + if m != nil { + return m.Ipk + } + return nil +} + +func (m *IdemixMSPConfig) GetSigner() *IdemixMSPSignerConfig { + if m != nil { + return m.Signer + } + return nil +} + +func (m *IdemixMSPConfig) GetRevocationPk() []byte { + if m != nil { + return m.RevocationPk + } + return nil +} + +func (m *IdemixMSPConfig) GetEpoch() int64 { + if m != nil { + return m.Epoch + } + return 0 +} + +func (m *IdemixMSPConfig) GetCurveId() string { + if m != nil { + return m.CurveId + } + return "" +} + +// IdemixMSPSIgnerConfig contains the crypto material to set up an idemix signing identity +type IdemixMSPSignerConfig struct { + // cred represents the serialized idemix credential of the default signer + Cred []byte `protobuf:"bytes,1,opt,name=cred,proto3" json:"cred,omitempty"` + // sk is the secret key of the default signer, corresponding to credential Cred + Sk []byte `protobuf:"bytes,2,opt,name=sk,proto3" json:"sk,omitempty"` + // organizational_unit_identifier defines the organizational unit the default signer is in + OrganizationalUnitIdentifier string `protobuf:"bytes,3,opt,name=organizational_unit_identifier,json=organizationalUnitIdentifier,proto3" json:"organizational_unit_identifier,omitempty"` + // role defines whether the default signer is admin, peer, member or client + Role int32 `protobuf:"varint,4,opt,name=role,proto3" json:"role,omitempty"` + // enrollment_id contains the enrollment id of this signer + EnrollmentId string `protobuf:"bytes,5,opt,name=enrollment_id,json=enrollmentId,proto3" json:"enrollment_id,omitempty"` + // credential_revocation_information contains a serialized CredentialRevocationInformation + CredentialRevocationInformation []byte `protobuf:"bytes,6,opt,name=credential_revocation_information,json=credentialRevocationInformation,proto3" json:"credential_revocation_information,omitempty"` + // RevocationHandle is the handle used to single out this credential and determine its revocation status + RevocationHandle string `protobuf:"bytes,7,opt,name=revocation_handle,json=revocationHandle,proto3" json:"revocation_handle,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *IdemixMSPSignerConfig) Reset() { *m = IdemixMSPSignerConfig{} } +func (m *IdemixMSPSignerConfig) String() string { return proto.CompactTextString(m) } +func (*IdemixMSPSignerConfig) ProtoMessage() {} +func (*IdemixMSPSignerConfig) Descriptor() ([]byte, []int) { + return fileDescriptor_783ba658a7862c73, []int{1} +} + +func (m *IdemixMSPSignerConfig) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_IdemixMSPSignerConfig.Unmarshal(m, b) +} +func (m *IdemixMSPSignerConfig) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_IdemixMSPSignerConfig.Marshal(b, m, deterministic) +} +func (m *IdemixMSPSignerConfig) XXX_Merge(src proto.Message) { + xxx_messageInfo_IdemixMSPSignerConfig.Merge(m, src) +} +func (m *IdemixMSPSignerConfig) XXX_Size() int { + return xxx_messageInfo_IdemixMSPSignerConfig.Size(m) +} +func (m *IdemixMSPSignerConfig) XXX_DiscardUnknown() { + xxx_messageInfo_IdemixMSPSignerConfig.DiscardUnknown(m) +} + +var xxx_messageInfo_IdemixMSPSignerConfig proto.InternalMessageInfo + +func (m *IdemixMSPSignerConfig) GetCred() []byte { + if m != nil { + return m.Cred + } + return nil +} + +func (m *IdemixMSPSignerConfig) GetSk() []byte { + if m != nil { + return m.Sk + } + return nil +} + +func (m *IdemixMSPSignerConfig) GetOrganizationalUnitIdentifier() string { + if m != nil { + return m.OrganizationalUnitIdentifier + } + return "" +} + +func (m *IdemixMSPSignerConfig) GetRole() int32 { + if m != nil { + return m.Role + } + return 0 +} + +func (m *IdemixMSPSignerConfig) GetEnrollmentId() string { + if m != nil { + return m.EnrollmentId + } + return "" +} + +func (m *IdemixMSPSignerConfig) GetCredentialRevocationInformation() []byte { + if m != nil { + return m.CredentialRevocationInformation + } + return nil +} + +func (m *IdemixMSPSignerConfig) GetRevocationHandle() string { + if m != nil { + return m.RevocationHandle + } + return "" +} + +func init() { + proto.RegisterType((*IdemixMSPConfig)(nil), "idemixmsp.IdemixMSPConfig") + proto.RegisterType((*IdemixMSPSignerConfig)(nil), "idemixmsp.IdemixMSPSignerConfig") +} + +func init() { proto.RegisterFile("idemixmsp/msp_config.proto", fileDescriptor_783ba658a7862c73) } + +var fileDescriptor_783ba658a7862c73 = []byte{ + // 428 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x92, 0x41, 0x8b, 0xd4, 0x30, + 0x14, 0xc7, 0x49, 0x67, 0x67, 0xd6, 0xc6, 0xee, 0xba, 0x06, 0x17, 0xaa, 0x88, 0x5b, 0xd7, 0xcb, + 0x80, 0x30, 0x03, 0x7a, 0xf1, 0x3c, 0x0a, 0x1a, 0x61, 0xa0, 0x64, 0x11, 0x16, 0x11, 0x4a, 0xb6, + 0xc9, 0xcc, 0x84, 0x36, 0x49, 0x49, 0x33, 0x8b, 0x78, 0xf6, 0x93, 0x78, 0xf4, 0xea, 0x87, 0x10, + 0xfc, 0x18, 0x1e, 0xfd, 0x14, 0x92, 0xd7, 0xdd, 0xb6, 0x82, 0xb7, 0xff, 0x7b, 0xf9, 0xf5, 0xff, + 0xde, 0x3f, 0x0d, 0x7e, 0xa4, 0x84, 0xd4, 0xea, 0xb3, 0x6e, 0x9b, 0xa5, 0x6e, 0x9b, 0xa2, 0xb4, + 0x66, 0xa3, 0xb6, 0x8b, 0xc6, 0x59, 0x6f, 0x49, 0xdc, 0x9f, 0x9d, 0xff, 0x44, 0xf8, 0x1e, 0x85, + 0x6a, 0x7d, 0x91, 0xbf, 0x06, 0x88, 0x10, 0x7c, 0x60, 0xb8, 0x96, 0x29, 0xca, 0xd0, 0x3c, 0x66, + 0xa0, 0xc9, 0x09, 0x9e, 0xa8, 0xa6, 0x4a, 0xa3, 0x0c, 0xcd, 0x13, 0x16, 0x24, 0x79, 0x85, 0x67, + 0xad, 0xda, 0x1a, 0xe9, 0xd2, 0x49, 0x86, 0xe6, 0x77, 0x5f, 0x64, 0x8b, 0xde, 0x75, 0xd1, 0x3b, + 0x5e, 0x00, 0xd1, 0xf9, 0xb2, 0x1b, 0x9e, 0x3c, 0xc3, 0x47, 0x4e, 0x5e, 0xdb, 0x92, 0x7b, 0x65, + 0x4d, 0xd1, 0x54, 0xe9, 0x01, 0xb8, 0x26, 0x43, 0x33, 0xaf, 0xc8, 0x03, 0x3c, 0x95, 0x8d, 0x2d, + 0x77, 0xe9, 0x34, 0x43, 0xf3, 0x09, 0xeb, 0x0a, 0xf2, 0x10, 0xdf, 0x29, 0xf7, 0xee, 0x5a, 0x16, + 0x4a, 0xa4, 0x33, 0x58, 0xef, 0x10, 0x6a, 0x2a, 0xce, 0x7f, 0x44, 0xf8, 0xf4, 0xbf, 0x73, 0x43, + 0x9e, 0xd2, 0x49, 0x01, 0x79, 0x12, 0x06, 0x9a, 0x1c, 0xe3, 0xa8, 0xbd, 0x8d, 0x13, 0xb5, 0x15, + 0x79, 0x83, 0x9f, 0x58, 0xb7, 0xe5, 0x46, 0x7d, 0x81, 0x05, 0x78, 0x5d, 0xec, 0x8d, 0xf2, 0x85, + 0x12, 0xd2, 0x78, 0xb5, 0x51, 0x37, 0x29, 0x63, 0xf6, 0xf8, 0x5f, 0xea, 0x83, 0x51, 0x9e, 0xf6, + 0x4c, 0x98, 0xe4, 0x6c, 0x2d, 0x21, 0xd0, 0x94, 0x81, 0x0e, 0x69, 0xa5, 0x71, 0xb6, 0xae, 0xb5, + 0x34, 0xc1, 0x10, 0x02, 0xc5, 0x2c, 0x19, 0x9a, 0x54, 0x90, 0xf7, 0xf8, 0x69, 0x58, 0x2b, 0x18, + 0xf1, 0xba, 0x18, 0xdd, 0x8e, 0x32, 0x1b, 0xeb, 0x34, 0x68, 0x08, 0x9c, 0xb0, 0xb3, 0x01, 0x64, + 0x3d, 0x47, 0x07, 0x8c, 0x3c, 0xc7, 0xf7, 0x47, 0x06, 0x3b, 0x6e, 0x44, 0x2d, 0xd3, 0x43, 0x18, + 0x7a, 0x32, 0x1c, 0xbc, 0x83, 0xfe, 0xea, 0x2b, 0xc2, 0x47, 0xa5, 0xd5, 0xc3, 0xbf, 0x5b, 0x1d, + 0xaf, 0xdb, 0xa6, 0xbb, 0xb8, 0x3c, 0x3c, 0x96, 0x1c, 0x7d, 0x3c, 0xdb, 0x2a, 0xbf, 0xdb, 0x5f, + 0x2d, 0x4a, 0xab, 0x97, 0x74, 0xb5, 0x5e, 0x76, 0xec, 0xb2, 0xff, 0xe4, 0x5b, 0x34, 0xa1, 0x97, + 0x97, 0xdf, 0xa3, 0x98, 0xde, 0x76, 0x7e, 0x8d, 0xf4, 0xef, 0xe8, 0xb4, 0xd7, 0x9f, 0xde, 0xe6, + 0xab, 0xb5, 0xf4, 0x5c, 0x70, 0xcf, 0xff, 0x8c, 0x98, 0xab, 0x19, 0x3c, 0xcc, 0x97, 0x7f, 0x03, + 0x00, 0x00, 0xff, 0xff, 0xe8, 0x8d, 0x2a, 0xd8, 0xb6, 0x02, 0x00, 0x00, +} diff --git a/vendor/github.com/IBM/idemix/idemixmsp/msp_config.proto b/vendor/github.com/IBM/idemix/idemixmsp/msp_config.proto new file mode 100644 index 00000000000..ea64dc2cba0 --- /dev/null +++ b/vendor/github.com/IBM/idemix/idemixmsp/msp_config.proto @@ -0,0 +1,56 @@ +// IdemixMSPConfig collects all the configuration information for +// an Idemix MSP. + + +// Copyright the Hyperledger Fabric contributors. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +syntax = "proto3"; +option go_package = "github.com/IBM/idemix/idemixmsp"; + +package idemixmsp; + +message IdemixMSPConfig { + // Name holds the identifier of the MSP + string name = 1; + + // ipk represents the (serialized) issuer public key + bytes ipk = 2; + + // signer may contain crypto material to configure a default signer + IdemixMSPSignerConfig signer = 3; + + // revocation_pk is the public key used for revocation of credentials + bytes revocation_pk = 4; + + // epoch represents the current epoch (time interval) used for revocation + int64 epoch = 5; + + // curve_id indicates which Elliptic Curve should be used + string curve_id = 6; + } + + // IdemixMSPSIgnerConfig contains the crypto material to set up an idemix signing identity + message IdemixMSPSignerConfig { + // cred represents the serialized idemix credential of the default signer + bytes cred = 1; + + // sk is the secret key of the default signer, corresponding to credential Cred + bytes sk = 2; + + // organizational_unit_identifier defines the organizational unit the default signer is in + string organizational_unit_identifier = 3; + + // role defines whether the default signer is admin, peer, member or client + int32 role = 4; + + // enrollment_id contains the enrollment id of this signer + string enrollment_id = 5; + + // credential_revocation_information contains a serialized CredentialRevocationInformation + bytes credential_revocation_information = 6; + + // RevocationHandle is the handle used to single out this credential and determine its revocation status + string revocation_handle = 7; +} \ No newline at end of file diff --git a/vendor/github.com/IBM/idemix/msp.go b/vendor/github.com/IBM/idemix/msp.go index b44279173e6..cc07a74135f 100644 --- a/vendor/github.com/IBM/idemix/msp.go +++ b/vendor/github.com/IBM/idemix/msp.go @@ -195,9 +195,10 @@ type ProviderType int // The ProviderType of a member relative to the member API const ( - FABRIC ProviderType = iota // MSP is of FABRIC type - IDEMIX // MSP is of IDEMIX type - OTHER // MSP is of OTHER TYPE + FABRIC ProviderType = iota // MSP is of FABRIC type + IDEMIX // MSP is of IDEMIX type + IDEMIX_ARIES // MSP is of IDEMIX_ARIES type + OTHER // MSP is of OTHER TYPE // NOTE: as new types are added to this set, // the mspTypes map below must be extended diff --git a/vendor/github.com/IBM/mathlib/Makefile b/vendor/github.com/IBM/mathlib/Makefile index cefc0f5020a..e4df705604c 100644 --- a/vendor/github.com/IBM/mathlib/Makefile +++ b/vendor/github.com/IBM/mathlib/Makefile @@ -15,6 +15,11 @@ unit-tests: unit-tests-race: @export GORACE=history_size=7; go test -timeout 960s -race -cover $(shell go list ./...) +.PHONY: perf +perf: + @go test -benchmem -bench=Benchmark_Sequential.* -run=^$$ -v + @go test -benchmem -bench=Benchmark_Parallel.* -run=^$$ -cpu=1,2,4,8,16,32,64 -v + .PHONY: check-deps check-deps: - @go get -u github.com/google/addlicense \ No newline at end of file + @go install github.com/google/addlicense@latest diff --git a/vendor/github.com/IBM/mathlib/driver/amcl/custom.go b/vendor/github.com/IBM/mathlib/driver/amcl/custom.go new file mode 100644 index 00000000000..6e627b638e7 --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/amcl/custom.go @@ -0,0 +1,31 @@ +/* +Copyright IBM Corp. All Rights Reserved. +Copyright (c) 2012-2020 MIRACL UK Ltd. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package amcl + +import ( + _ "unsafe" + + "github.com/hyperledger/fabric-amcl/core" + "github.com/hyperledger/fabric-amcl/core/FP256BN" +) + +const HASH_TYPE int = 32 + +//go:linkname hash_to_field github.com/hyperledger/fabric-amcl/core/FP256BN.hash_to_field +func hash_to_field(hash int, hlen int, DST []byte, M []byte, ctr int) []*FP256BN.FP + +func bls_hash_to_point_miracl(M, DST []byte) *FP256BN.ECP { + u := hash_to_field(core.MC_SHA2, HASH_TYPE, DST, M, 2) + + P := FP256BN.ECP_map2point(u[0]) + P1 := FP256BN.ECP_map2point(u[1]) + P.Add(P1) + P.Cfp() + P.Affine() + return P +} diff --git a/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn.go b/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn.go index 9de4b7ab0c2..9a9d55d39c6 100644 --- a/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn.go +++ b/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn.go @@ -7,75 +7,29 @@ SPDX-License-Identifier: Apache-2.0 package amcl import ( - r "crypto/rand" + "crypto/hmac" "crypto/sha256" - "io" "math/big" "regexp" "strings" "github.com/IBM/mathlib/driver" "github.com/IBM/mathlib/driver/common" - "github.com/hyperledger/fabric-amcl/amcl" "github.com/hyperledger/fabric-amcl/amcl/FP256BN" - "github.com/pkg/errors" ) /*********************************************************************/ -type fp256bnZr struct { - *FP256BN.BIG -} - -func (b *fp256bnZr) Plus(a driver.Zr) driver.Zr { - return &fp256bnZr{b.BIG.Plus(a.(*fp256bnZr).BIG)} -} - -func (b *fp256bnZr) PowMod(x driver.Zr) driver.Zr { - q := FP256BN.NewBIGints(FP256BN.CURVE_Order) - - return &fp256bnZr{b.BIG.Powmod(x.(*fp256bnZr).BIG, q)} -} - -func (b *fp256bnZr) Mod(a driver.Zr) { - b.BIG.Mod(a.(*fp256bnZr).BIG) -} - -func (b *fp256bnZr) InvModP(p driver.Zr) { - b.BIG.Invmodp(p.(*fp256bnZr).BIG) -} - -func (b *fp256bnZr) Bytes() []byte { - by := make([]byte, int(FP256BN.MODBYTES)) - b.BIG.ToBytes(by) - return by -} - -func (b *fp256bnZr) Equals(p driver.Zr) bool { - return *b.BIG == *(p.(*fp256bnZr).BIG) -} - -func (b *fp256bnZr) Copy() driver.Zr { - return &fp256bnZr{FP256BN.NewBIGcopy(b.BIG)} -} - -func (b *fp256bnZr) Clone(a driver.Zr) { - c := a.Copy() - b.BIG = c.(*fp256bnZr).BIG +type fp256bnGt struct { + FP256BN.FP12 } -func (b *fp256bnZr) String() string { - return strings.TrimLeft(b.BIG.ToString(), "0") -} - -/*********************************************************************/ - -type fp256bnGt struct { - *FP256BN.FP12 +func (a *fp256bnGt) Exp(x driver.Zr) driver.Gt { + return &fp256bnGt{*a.FP12.Pow(bigToMiraclBIGCore(&x.(*common.BaseZr).Int))} } func (a *fp256bnGt) Equals(b driver.Gt) bool { - return a.FP12.Equals(b.(*fp256bnGt).FP12) + return a.FP12.Equals(&b.(*fp256bnGt).FP12) } func (a *fp256bnGt) IsUnity() bool { @@ -87,7 +41,7 @@ func (a *fp256bnGt) Inverse() { } func (a *fp256bnGt) Mul(b driver.Gt) { - a.FP12.Mul(b.(*fp256bnGt).FP12) + a.FP12.Mul(&b.(*fp256bnGt).FP12) } func (b *fp256bnGt) ToString() string { @@ -102,180 +56,146 @@ func (b *fp256bnGt) Bytes() []byte { /*********************************************************************/ +func NewFp256bn() *Fp256bn { + return &Fp256bn{common.CurveBase{Modulus: modulusBig}} +} + type Fp256bn struct { + common.CurveBase } func (*Fp256bn) Pairing(a driver.G2, b driver.G1) driver.Gt { - return &fp256bnGt{FP256BN.Ate(a.(*fp256bnG2).ECP2, b.(*fp256bnG1).ECP)} + return &fp256bnGt{*FP256BN.Ate(&a.(*fp256bnG2).ECP2, &b.(*fp256bnG1).ECP)} } func (*Fp256bn) Pairing2(p2a, p2b driver.G2, p1a, p1b driver.G1) driver.Gt { - return &fp256bnGt{FP256BN.Ate2(p2a.(*fp256bnG2).ECP2, p1a.(*fp256bnG1).ECP, p2b.(*fp256bnG2).ECP2, p1b.(*fp256bnG1).ECP)} + return &fp256bnGt{*FP256BN.Ate2(&p2a.(*fp256bnG2).ECP2, &p1a.(*fp256bnG1).ECP, &p2b.(*fp256bnG2).ECP2, &p1b.(*fp256bnG1).ECP)} } func (*Fp256bn) FExp(e driver.Gt) driver.Gt { - return &fp256bnGt{FP256BN.Fexp(e.(*fp256bnGt).FP12)} -} - -func (*Fp256bn) ModMul(a1, b1, m driver.Zr) driver.Zr { - return &fp256bnZr{FP256BN.Modmul(a1.(*fp256bnZr).BIG, b1.(*fp256bnZr).BIG, m.(*fp256bnZr).BIG)} -} - -func (*Fp256bn) ModNeg(a1, m driver.Zr) driver.Zr { - return &fp256bnZr{FP256BN.Modneg(a1.(*fp256bnZr).BIG, m.(*fp256bnZr).BIG)} + return &fp256bnGt{*FP256BN.Fexp(&e.(*fp256bnGt).FP12)} } func (*Fp256bn) GenG1() driver.G1 { - return &fp256bnG1{FP256BN.NewECPbigs(FP256BN.NewBIGints(FP256BN.CURVE_Gx), FP256BN.NewBIGints(FP256BN.CURVE_Gy))} + return &fp256bnG1{*FP256BN.NewECPbigs(FP256BN.NewBIGints(FP256BN.CURVE_Gx), FP256BN.NewBIGints(FP256BN.CURVE_Gy))} } func (*Fp256bn) GenG2() driver.G2 { - return &fp256bnG2{FP256BN.NewECP2fp2s( + return &fp256bnG2{*FP256BN.NewECP2fp2s( FP256BN.NewFP2bigs(FP256BN.NewBIGints(FP256BN.CURVE_Pxa), FP256BN.NewBIGints(FP256BN.CURVE_Pxb)), FP256BN.NewFP2bigs(FP256BN.NewBIGints(FP256BN.CURVE_Pya), FP256BN.NewBIGints(FP256BN.CURVE_Pyb)))} } func (p *Fp256bn) GenGt() driver.Gt { - return &fp256bnGt{FP256BN.Fexp(FP256BN.Ate(p.GenG2().(*fp256bnG2).ECP2, p.GenG1().(*fp256bnG1).ECP))} + return &fp256bnGt{*FP256BN.Fexp(FP256BN.Ate(&p.GenG2().(*fp256bnG2).ECP2, &p.GenG1().(*fp256bnG1).ECP))} } -func (p *Fp256bn) GroupOrder() driver.Zr { - return &fp256bnZr{FP256BN.NewBIGints(FP256BN.CURVE_Order)} +func (p *Fp256bn) CoordinateByteSize() int { + return int(FP256BN.MODBYTES) } -func (p *Fp256bn) FieldBytes() int { - return int(FP256BN.MODBYTES) +func (p *Fp256bn) G1ByteSize() int { + return 2*int(FP256BN.MODBYTES) + 1 } -func (p *Fp256bn) NewG1() driver.G1 { - return &fp256bnG1{FP256BN.NewECP()} +func (p *Fp256bn) CompressedG1ByteSize() int { + return int(FP256BN.MODBYTES) + 1 } -func (p *Fp256bn) NewG2() driver.G2 { - return &fp256bnG2{FP256BN.NewECP2()} +func (p *Fp256bn) G2ByteSize() int { + return 4 * int(FP256BN.MODBYTES) } -func (p *Fp256bn) NewG1FromCoords(ix, iy driver.Zr) driver.G1 { - return &fp256bnG1{FP256BN.NewECPbigs(ix.(*fp256bnZr).BIG, iy.(*fp256bnZr).BIG)} +func (p *Fp256bn) CompressedG2ByteSize() int { + return 4 * int(FP256BN.MODBYTES) } -func (p *Fp256bn) NewZrFromBytes(b []byte) driver.Zr { - return &fp256bnZr{FP256BN.FromBytes(b)} +func (p *Fp256bn) ScalarByteSize() int { + return common.ScalarByteSize } -func (p *Fp256bn) NewZrFromInt(i int64) driver.Zr { - var i0, i1, i2, i3, i4 int64 +func (p *Fp256bn) NewG1() driver.G1 { + return &fp256bnG1{*FP256BN.NewECP()} +} - sign := int64(1) - if i < 0 { - sign = -1 - } +func (p *Fp256bn) NewG2() driver.G2 { + return &fp256bnG2{*FP256BN.NewECP2()} +} + +func bigToMiraclBIGCore(bi *big.Int) *FP256BN.BIG { + biCopy := bi - b := common.BigToBytes(big.NewInt(i * sign)) - - pos := 32 - i0 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i1 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i2 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i3 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i4 = new(big.Int).SetBytes(b[0:pos]).Int64() - - zr := FP256BN.NewBIGints([FP256BN.NLEN]FP256BN.Chunk{FP256BN.Chunk(i0), FP256BN.Chunk(i1), FP256BN.Chunk(i2), FP256BN.Chunk(i3), FP256BN.Chunk(i4)}) - if sign < 0 { - zr = FP256BN.NewBIGint(0).Minus(zr) + if bi.Sign() < 0 || bi.Cmp(&modulusBig) > 0 { + biCopy = new(big.Int).Set(bi) + biCopy = biCopy.Mod(biCopy, &modulusBig) + if biCopy.Sign() < 0 { + biCopy = biCopy.Add(biCopy, &modulusBig) + } } - return &fp256bnZr{zr} + return FP256BN.FromBytes(common.BigToBytes(biCopy)) } func (p *Fp256bn) NewG1FromBytes(b []byte) driver.G1 { - return &fp256bnG1{FP256BN.ECP_fromBytes(b)} + return &fp256bnG1{*FP256BN.ECP_fromBytes(b)} } func (p *Fp256bn) NewG2FromBytes(b []byte) driver.G2 { - return &fp256bnG2{FP256BN.ECP2_fromBytes(b)} + return &fp256bnG2{*FP256BN.ECP2_fromBytes(b)} } -func (p *Fp256bn) NewGtFromBytes(b []byte) driver.Gt { - return &fp256bnGt{FP256BN.FP12_fromBytes(b)} -} - -func (p *Fp256bn) ModAdd(a, b, m driver.Zr) driver.Zr { - c := a.Plus(b) - c.Mod(m) - return c +func (p *Fp256bn) NewG1FromCompressed(b []byte) driver.G1 { + return &fp256bnG1{*FP256BN.ECP_fromBytes(b)} } -func (p *Fp256bn) ModSub(a, b, m driver.Zr) driver.Zr { - return p.ModAdd(a, p.ModNeg(b, m), m) +func (p *Fp256bn) NewG2FromCompressed(b []byte) driver.G2 { + return &fp256bnG2{*FP256BN.ECP2_fromBytes(b)} } -func (p *Fp256bn) HashToZr(data []byte) driver.Zr { - digest := sha256.Sum256(data) - digestBig := FP256BN.FromBytes(digest[:]) - digestBig.Mod(FP256BN.NewBIGints(FP256BN.CURVE_Order)) - return &fp256bnZr{digestBig} +func (p *Fp256bn) NewGtFromBytes(b []byte) driver.Gt { + return &fp256bnGt{*FP256BN.FP12_fromBytes(b)} } func (p *Fp256bn) HashToG1(data []byte) driver.G1 { - return &fp256bnG1{FP256BN.Bls_hash(string(data))} + return &fp256bnG1{*FP256BN.Bls_hash(string(data))} } -func (p *Fp256bn) Rand() (io.Reader, error) { - seedLength := 32 - b := make([]byte, seedLength) - _, err := r.Read(b) - if err != nil { - return nil, errors.Wrap(err, "error getting randomness for seed") - } - rng := amcl.NewRAND() - rng.Clean() - rng.Seed(seedLength, b) - return &rand{rng}, nil -} - -func (p *Fp256bn) NewRandomZr(rng io.Reader) driver.Zr { - // curve order q - q := FP256BN.NewBIGints(FP256BN.CURVE_Order) - - // Take random element in Zq - return &fp256bnZr{FP256BN.Randomnum(q, rng.(*rand).R)} +func (p *Fp256bn) HashToG1WithDomain(data, domain []byte) driver.G1 { + mac := hmac.New(sha256.New, domain) + mac.Write(data) + return &fp256bnG1{*FP256BN.Bls_hash(string(mac.Sum(nil)))} } /*********************************************************************/ type fp256bnG1 struct { - *FP256BN.ECP + FP256BN.ECP } func (e *fp256bnG1) Clone(a driver.G1) { - e.ECP.Copy(a.(*fp256bnG1).ECP) + e.ECP.Copy(&a.(*fp256bnG1).ECP) } func (e *fp256bnG1) Copy() driver.G1 { c := FP256BN.NewECP() - c.Copy(e.ECP) - return &fp256bnG1{c} + c.Copy(&e.ECP) + return &fp256bnG1{*c} } func (e *fp256bnG1) Add(a driver.G1) { - e.ECP.Add(a.(*fp256bnG1).ECP) + e.ECP.Add(&a.(*fp256bnG1).ECP) } func (e *fp256bnG1) Mul(a driver.Zr) driver.G1 { - return &fp256bnG1{FP256BN.G1mul(e.ECP, a.(*fp256bnZr).BIG)} + return &fp256bnG1{*FP256BN.G1mul(&e.ECP, bigToMiraclBIGCore(&a.(*common.BaseZr).Int))} } func (e *fp256bnG1) Mul2(ee driver.Zr, Q driver.G1, f driver.Zr) driver.G1 { - return &fp256bnG1{e.ECP.Mul2(ee.(*fp256bnZr).BIG, Q.(*fp256bnG1).ECP, f.(*fp256bnZr).BIG)} + return &fp256bnG1{*e.ECP.Mul2(bigToMiraclBIGCore(&ee.(*common.BaseZr).Int), &Q.(*fp256bnG1).ECP, bigToMiraclBIGCore(&f.(*common.BaseZr).Int))} } func (e *fp256bnG1) Equals(a driver.G1) bool { - return e.ECP.Equals(a.(*fp256bnG1).ECP) + return e.ECP.Equals(&a.(*fp256bnG1).ECP) } func (e *fp256bnG1) IsInfinity() bool { @@ -288,8 +208,14 @@ func (e *fp256bnG1) Bytes() []byte { return b } +func (e *fp256bnG1) Compressed() []byte { + b := make([]byte, int(FP256BN.MODBYTES)+1) + e.ECP.ToBytes(b, true) + return b +} + func (e *fp256bnG1) Sub(a driver.G1) { - e.ECP.Sub(a.(*fp256bnG1).ECP) + e.ECP.Sub(&a.(*fp256bnG1).ECP) } var g1StrRegexp *regexp.Regexp = regexp.MustCompile(`^\(([0-9a-f]+),([0-9a-f]+)\)$`) @@ -300,36 +226,41 @@ func (b *fp256bnG1) String() string { return "(" + strings.TrimLeft(m[0][1], "0") + "," + strings.TrimLeft(m[0][2], "0") + ")" } +func (e *fp256bnG1) Neg() { + res := e.Mul(NewFp256bn().NewZrFromInt(-1)) + e.ECP = res.(*fp256bnG1).ECP +} + /*********************************************************************/ type fp256bnG2 struct { - *FP256BN.ECP2 + FP256BN.ECP2 } func (e *fp256bnG2) Equals(a driver.G2) bool { - return e.ECP2.Equals(a.(*fp256bnG2).ECP2) + return e.ECP2.Equals(&a.(*fp256bnG2).ECP2) } func (e *fp256bnG2) Clone(a driver.G2) { - e.ECP2.Copy(a.(*fp256bnG2).ECP2) + e.ECP2.Copy(&a.(*fp256bnG2).ECP2) } func (e *fp256bnG2) Copy() driver.G2 { c := FP256BN.NewECP2() - c.Copy(e.ECP2) - return &fp256bnG2{c} + c.Copy(&e.ECP2) + return &fp256bnG2{*c} } func (e *fp256bnG2) Add(a driver.G2) { - e.ECP2.Add(a.(*fp256bnG2).ECP2) + e.ECP2.Add(&a.(*fp256bnG2).ECP2) } func (e *fp256bnG2) Sub(a driver.G2) { - e.ECP2.Sub(a.(*fp256bnG2).ECP2) + e.ECP2.Sub(&a.(*fp256bnG2).ECP2) } func (e *fp256bnG2) Mul(a driver.Zr) driver.G2 { - return &fp256bnG2{e.ECP2.Mul(a.(*fp256bnZr).BIG)} + return &fp256bnG2{*e.ECP2.Mul(bigToMiraclBIGCore(&a.(*common.BaseZr).Int))} } func (e *fp256bnG2) Affine() { @@ -342,24 +273,12 @@ func (e *fp256bnG2) Bytes() []byte { return b } -func (b *fp256bnG2) String() string { - return b.ECP2.ToString() -} - -/*********************************************************************/ - -type rand struct { - R *amcl.RAND -} - -func (*rand) Read(p []byte) (n int, err error) { - panic("not used") +func (e *fp256bnG2) Compressed() []byte { + b := make([]byte, 4*int(FP256BN.MODBYTES)) + e.ECP2.ToBytes(b) + return b } -/*********************************************************************/ - -func bigToBytes(big *FP256BN.BIG) []byte { - ret := make([]byte, int(FP256BN.MODBYTES)) - big.ToBytes(ret) - return ret +func (b *fp256bnG2) String() string { + return b.ECP2.ToString() } diff --git a/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn_miracl.go b/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn_miracl.go index 5a65694a47c..541bccd28ea 100644 --- a/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn_miracl.go +++ b/vendor/github.com/IBM/mathlib/driver/amcl/fp256bn_miracl.go @@ -7,74 +7,33 @@ SPDX-License-Identifier: Apache-2.0 package amcl import ( - r "crypto/rand" - "crypto/sha256" - "io" "math/big" "strings" "github.com/IBM/mathlib/driver" "github.com/IBM/mathlib/driver/common" - "github.com/hyperledger/fabric-amcl/core" "github.com/hyperledger/fabric-amcl/core/FP256BN" - "github.com/pkg/errors" ) /*********************************************************************/ -type fp256bnMiraclZr struct { - *FP256BN.BIG -} - -func (b *fp256bnMiraclZr) Plus(a driver.Zr) driver.Zr { - return &fp256bnMiraclZr{b.BIG.Plus(a.(*fp256bnMiraclZr).BIG)} -} - -func (b *fp256bnMiraclZr) PowMod(x driver.Zr) driver.Zr { - q := FP256BN.NewBIGints(FP256BN.CURVE_Order) - - return &fp256bnMiraclZr{b.BIG.Powmod(x.(*fp256bnMiraclZr).BIG, q)} -} - -func (b *fp256bnMiraclZr) Mod(a driver.Zr) { - b.BIG.Mod(a.(*fp256bnMiraclZr).BIG) -} - -func (b *fp256bnMiraclZr) InvModP(p driver.Zr) { - b.BIG.Invmodp(p.(*fp256bnMiraclZr).BIG) -} - -func (b *fp256bnMiraclZr) Bytes() []byte { - by := make([]byte, int(FP256BN.MODBYTES)) - b.BIG.ToBytes(by) - return by -} - -func (b *fp256bnMiraclZr) Equals(p driver.Zr) bool { - return *b.BIG == *(p.(*fp256bnMiraclZr).BIG) -} - -func (b *fp256bnMiraclZr) Copy() driver.Zr { - return &fp256bnMiraclZr{FP256BN.NewBIGcopy(b.BIG)} -} - -func (b *fp256bnMiraclZr) Clone(a driver.Zr) { - c := a.Copy() - b.BIG = c.(*fp256bnMiraclZr).BIG -} - -func (b *fp256bnMiraclZr) String() string { - return strings.TrimLeft(b.BIG.ToString(), "0") +var modulusBig big.Int // q stored as big.Int +func init() { + modulusBig.SetString("fffffffffffcf0cd46e5f25eee71a49e0cdc65fb1299921af62d536cd10b500d", 16) } /*********************************************************************/ type fp256bnMiraclGt struct { - *FP256BN.FP12 + FP256BN.FP12 +} + +func (a *fp256bnMiraclGt) Exp(x driver.Zr) driver.Gt { + return &fp256bnMiraclGt{*a.FP12.Pow(bigToMiraclBIG(&x.(*common.BaseZr).Int))} } func (a *fp256bnMiraclGt) Equals(b driver.Gt) bool { - return a.FP12.Equals(b.(*fp256bnMiraclGt).FP12) + return a.FP12.Equals(&b.(*fp256bnMiraclGt).FP12) } func (a *fp256bnMiraclGt) IsUnity() bool { @@ -86,7 +45,7 @@ func (a *fp256bnMiraclGt) Inverse() { } func (a *fp256bnMiraclGt) Mul(b driver.Gt) { - a.FP12.Mul(b.(*fp256bnMiraclGt).FP12) + a.FP12.Mul(&b.(*fp256bnMiraclGt).FP12) } func (b *fp256bnMiraclGt) ToString() string { @@ -101,31 +60,28 @@ func (b *fp256bnMiraclGt) Bytes() []byte { /*********************************************************************/ +func NewFp256Miraclbn() *Fp256Miraclbn { + return &Fp256Miraclbn{common.CurveBase{Modulus: modulusBig}} +} + type Fp256Miraclbn struct { + common.CurveBase } func (*Fp256Miraclbn) Pairing(a driver.G2, b driver.G1) driver.Gt { - return &fp256bnMiraclGt{FP256BN.Ate(a.(*fp256bnMiraclG2).ECP2, b.(*fp256bnMiraclG1).ECP)} + return &fp256bnMiraclGt{*FP256BN.Ate(a.(*fp256bnMiraclG2).ECP2, &b.(*fp256bnMiraclG1).ECP)} } func (*Fp256Miraclbn) Pairing2(p2a, p2b driver.G2, p1a, p1b driver.G1) driver.Gt { - return &fp256bnMiraclGt{FP256BN.Ate2(p2a.(*fp256bnMiraclG2).ECP2, p1a.(*fp256bnMiraclG1).ECP, p2b.(*fp256bnMiraclG2).ECP2, p1b.(*fp256bnMiraclG1).ECP)} + return &fp256bnMiraclGt{*FP256BN.Ate2(p2a.(*fp256bnMiraclG2).ECP2, &p1a.(*fp256bnMiraclG1).ECP, p2b.(*fp256bnMiraclG2).ECP2, &p1b.(*fp256bnMiraclG1).ECP)} } func (*Fp256Miraclbn) FExp(e driver.Gt) driver.Gt { - return &fp256bnMiraclGt{FP256BN.Fexp(e.(*fp256bnMiraclGt).FP12)} -} - -func (*Fp256Miraclbn) ModMul(a1, b1, m driver.Zr) driver.Zr { - return &fp256bnMiraclZr{FP256BN.Modmul(a1.(*fp256bnMiraclZr).BIG, b1.(*fp256bnMiraclZr).BIG, m.(*fp256bnMiraclZr).BIG)} -} - -func (*Fp256Miraclbn) ModNeg(a1, m driver.Zr) driver.Zr { - return &fp256bnMiraclZr{FP256BN.Modneg(a1.(*fp256bnMiraclZr).BIG, m.(*fp256bnMiraclZr).BIG)} + return &fp256bnMiraclGt{*FP256BN.Fexp(&e.(*fp256bnMiraclGt).FP12)} } func (*Fp256Miraclbn) GenG1() driver.G1 { - return &fp256bnMiraclG1{FP256BN.NewECPbigs(FP256BN.NewBIGints(FP256BN.CURVE_Gx), FP256BN.NewBIGints(FP256BN.CURVE_Gy))} + return &fp256bnMiraclG1{*FP256BN.NewECPbigs(FP256BN.NewBIGints(FP256BN.CURVE_Gx), FP256BN.NewBIGints(FP256BN.CURVE_Gy))} } func (*Fp256Miraclbn) GenG2() driver.G2 { @@ -135,148 +91,113 @@ func (*Fp256Miraclbn) GenG2() driver.G2 { } func (p *Fp256Miraclbn) GenGt() driver.Gt { - return &fp256bnMiraclGt{FP256BN.Fexp(FP256BN.Ate(p.GenG2().(*fp256bnMiraclG2).ECP2, p.GenG1().(*fp256bnMiraclG1).ECP))} + return &fp256bnMiraclGt{*FP256BN.Fexp(FP256BN.Ate(p.GenG2().(*fp256bnMiraclG2).ECP2, &p.GenG1().(*fp256bnMiraclG1).ECP))} } -func (p *Fp256Miraclbn) GroupOrder() driver.Zr { - return &fp256bnMiraclZr{FP256BN.NewBIGints(FP256BN.CURVE_Order)} +func (p *Fp256Miraclbn) CoordinateByteSize() int { + return int(FP256BN.MODBYTES) } -func (p *Fp256Miraclbn) FieldBytes() int { - return int(FP256BN.MODBYTES) +func (p *Fp256Miraclbn) G1ByteSize() int { + return 2*int(FP256BN.MODBYTES) + 1 } -func (p *Fp256Miraclbn) NewG1() driver.G1 { - return &fp256bnMiraclG1{FP256BN.NewECP()} +func (p *Fp256Miraclbn) CompressedG1ByteSize() int { + return int(FP256BN.MODBYTES) + 1 } -func (p *Fp256Miraclbn) NewG2() driver.G2 { - return &fp256bnMiraclG2{FP256BN.NewECP2()} +func (p *Fp256Miraclbn) G2ByteSize() int { + return 4*int(FP256BN.MODBYTES) + 1 } -func (p *Fp256Miraclbn) NewG1FromCoords(ix, iy driver.Zr) driver.G1 { - return &fp256bnMiraclG1{FP256BN.NewECPbigs(ix.(*fp256bnMiraclZr).BIG, iy.(*fp256bnMiraclZr).BIG)} +func (p *Fp256Miraclbn) CompressedG2ByteSize() int { + return 2*int(FP256BN.MODBYTES) + 1 } -func (p *Fp256Miraclbn) NewZrFromBytes(b []byte) driver.Zr { - return &fp256bnMiraclZr{FP256BN.FromBytes(b)} +func (p *Fp256Miraclbn) ScalarByteSize() int { + return common.ScalarByteSize } -func (p *Fp256Miraclbn) NewZrFromInt(i int64) driver.Zr { - var i0, i1, i2, i3, i4 int64 +func (p *Fp256Miraclbn) NewG1() driver.G1 { + return &fp256bnMiraclG1{*FP256BN.NewECP()} +} - sign := int64(1) - if i < 0 { - sign = -1 - } +func (p *Fp256Miraclbn) NewG2() driver.G2 { + return &fp256bnMiraclG2{FP256BN.NewECP2()} +} + +func bigToMiraclBIG(bi *big.Int) *FP256BN.BIG { + biCopy := bi - b := common.BigToBytes(big.NewInt(i * sign)) - - pos := 32 - i0 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i1 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i2 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i3 = new(big.Int).SetBytes(b[pos-7 : pos]).Int64() - pos -= 7 - i4 = new(big.Int).SetBytes(b[0:pos]).Int64() - - zr := FP256BN.NewBIGints([FP256BN.NLEN]FP256BN.Chunk{FP256BN.Chunk(i0), FP256BN.Chunk(i1), FP256BN.Chunk(i2), FP256BN.Chunk(i3), FP256BN.Chunk(i4)}) - if sign < 0 { - zr = FP256BN.NewBIGint(0).Minus(zr) + if bi.Sign() < 0 || bi.Cmp(&modulusBig) > 0 { + biCopy = new(big.Int).Set(bi) + biCopy = biCopy.Mod(biCopy, &modulusBig) + if biCopy.Sign() < 0 { + biCopy = biCopy.Add(biCopy, &modulusBig) + } } - return &fp256bnMiraclZr{zr} + return FP256BN.FromBytes(common.BigToBytes(biCopy)) } func (p *Fp256Miraclbn) NewG1FromBytes(b []byte) driver.G1 { - return &fp256bnMiraclG1{FP256BN.ECP_fromBytes(b)} + return &fp256bnMiraclG1{*FP256BN.ECP_fromBytes(b)} } func (p *Fp256Miraclbn) NewG2FromBytes(b []byte) driver.G2 { return &fp256bnMiraclG2{FP256BN.ECP2_fromBytes(b)} } -func (p *Fp256Miraclbn) NewGtFromBytes(b []byte) driver.Gt { - return &fp256bnMiraclGt{FP256BN.FP12_fromBytes(b)} -} - -func (p *Fp256Miraclbn) ModAdd(a, b, m driver.Zr) driver.Zr { - c := a.Plus(b) - c.Mod(m) - return c +func (p *Fp256Miraclbn) NewG1FromCompressed(b []byte) driver.G1 { + return &fp256bnMiraclG1{*FP256BN.ECP_fromBytes(b)} } -func (p *Fp256Miraclbn) ModSub(a, b, m driver.Zr) driver.Zr { - return p.ModAdd(a, p.ModNeg(b, m), m) +func (p *Fp256Miraclbn) NewG2FromCompressed(b []byte) driver.G2 { + return &fp256bnMiraclG2{FP256BN.ECP2_fromBytes(b)} } -func (p *Fp256Miraclbn) HashToZr(data []byte) driver.Zr { - digest := sha256.Sum256(data) - digestBig := FP256BN.FromBytes(digest[:]) - digestBig.Mod(FP256BN.NewBIGints(FP256BN.CURVE_Order)) - return &fp256bnMiraclZr{digestBig} +func (p *Fp256Miraclbn) NewGtFromBytes(b []byte) driver.Gt { + return &fp256bnMiraclGt{*FP256BN.FP12_fromBytes(b)} } func (p *Fp256Miraclbn) HashToG1(data []byte) driver.G1 { - zr := p.HashToZr(data) - fp := FP256BN.NewFPbig(zr.(*fp256bnMiraclZr).BIG) - return &fp256bnMiraclG1{FP256BN.ECP_map2point(fp)} -} - -func (p *Fp256Miraclbn) Rand() (io.Reader, error) { - seedLength := 32 - b := make([]byte, seedLength) - _, err := r.Read(b) - if err != nil { - return nil, errors.Wrap(err, "error getting randomness for seed") - } - rng := core.NewRAND() - rng.Clean() - rng.Seed(seedLength, b) - return &randMiracl{rng}, nil + return &fp256bnMiraclG1{*bls_hash_to_point_miracl(data, []byte{})} } -func (p *Fp256Miraclbn) NewRandomZr(rng io.Reader) driver.Zr { - // curve order q - q := FP256BN.NewBIGints(FP256BN.CURVE_Order) - - // Take random element in Zq - return &fp256bnMiraclZr{FP256BN.Randomnum(q, rng.(*randMiracl).R)} +func (p *Fp256Miraclbn) HashToG1WithDomain(data, domain []byte) driver.G1 { + return &fp256bnMiraclG1{*bls_hash_to_point_miracl(data, domain)} } /*********************************************************************/ type fp256bnMiraclG1 struct { - *FP256BN.ECP + FP256BN.ECP } func (e *fp256bnMiraclG1) Clone(a driver.G1) { - e.ECP.Copy(a.(*fp256bnMiraclG1).ECP) + e.ECP.Copy(&a.(*fp256bnMiraclG1).ECP) } func (e *fp256bnMiraclG1) Copy() driver.G1 { c := FP256BN.NewECP() - c.Copy(e.ECP) - return &fp256bnMiraclG1{c} + c.Copy(&e.ECP) + return &fp256bnMiraclG1{*c} } func (e *fp256bnMiraclG1) Add(a driver.G1) { - e.ECP.Add(a.(*fp256bnMiraclG1).ECP) + e.ECP.Add(&a.(*fp256bnMiraclG1).ECP) } func (e *fp256bnMiraclG1) Mul(a driver.Zr) driver.G1 { - return &fp256bnMiraclG1{FP256BN.G1mul(e.ECP, a.(*fp256bnMiraclZr).BIG)} + return &fp256bnMiraclG1{*FP256BN.G1mul(&e.ECP, bigToMiraclBIG(&a.(*common.BaseZr).Int))} } func (e *fp256bnMiraclG1) Mul2(ee driver.Zr, Q driver.G1, f driver.Zr) driver.G1 { - return &fp256bnMiraclG1{e.ECP.Mul2(ee.(*fp256bnMiraclZr).BIG, Q.(*fp256bnMiraclG1).ECP, f.(*fp256bnMiraclZr).BIG)} + return &fp256bnMiraclG1{*e.ECP.Mul2(bigToMiraclBIG(&ee.(*common.BaseZr).Int), &Q.(*fp256bnMiraclG1).ECP, bigToMiraclBIG(&f.(*common.BaseZr).Int))} } func (e *fp256bnMiraclG1) Equals(a driver.G1) bool { - return e.ECP.Equals(a.(*fp256bnMiraclG1).ECP) + return e.ECP.Equals(&a.(*fp256bnMiraclG1).ECP) } func (e *fp256bnMiraclG1) IsInfinity() bool { @@ -289,8 +210,14 @@ func (e *fp256bnMiraclG1) Bytes() []byte { return b } +func (e *fp256bnMiraclG1) Compressed() []byte { + b := make([]byte, int(FP256BN.MODBYTES)+1) + e.ECP.ToBytes(b, true) + return b +} + func (e *fp256bnMiraclG1) Sub(a driver.G1) { - e.ECP.Sub(a.(*fp256bnMiraclG1).ECP) + e.ECP.Sub(&a.(*fp256bnMiraclG1).ECP) } func (b *fp256bnMiraclG1) String() string { @@ -299,6 +226,10 @@ func (b *fp256bnMiraclG1) String() string { return "(" + strings.TrimLeft(m[0][1], "0") + "," + strings.TrimLeft(m[0][2], "0") + ")" } +func (e *fp256bnMiraclG1) Neg() { + e.ECP.Neg() +} + /*********************************************************************/ type fp256bnMiraclG2 struct { @@ -328,7 +259,7 @@ func (e *fp256bnMiraclG2) Sub(a driver.G2) { } func (e *fp256bnMiraclG2) Mul(a driver.Zr) driver.G2 { - return &fp256bnMiraclG2{e.ECP2.Mul(a.(*fp256bnMiraclZr).BIG)} + return &fp256bnMiraclG2{e.ECP2.Mul(bigToMiraclBIG(&a.(*common.BaseZr).Int))} } func (e *fp256bnMiraclG2) Affine() { @@ -341,24 +272,12 @@ func (e *fp256bnMiraclG2) Bytes() []byte { return b } -func (b *fp256bnMiraclG2) String() string { - return b.ECP2.ToString() -} - -/*********************************************************************/ - -type randMiracl struct { - R *core.RAND -} - -func (*randMiracl) Read(p []byte) (n int, err error) { - panic("not used") +func (e *fp256bnMiraclG2) Compressed() []byte { + b := make([]byte, 2*int(FP256BN.MODBYTES)+1) + e.ECP2.ToBytes(b, true) + return b } -/*********************************************************************/ - -func bigToBytesMiracl(big *FP256BN.BIG) []byte { - ret := make([]byte, int(FP256BN.MODBYTES)) - big.ToBytes(ret) - return ret +func (b *fp256bnMiraclG2) String() string { + return b.ECP2.ToString() } diff --git a/vendor/github.com/IBM/mathlib/driver/common/big.go b/vendor/github.com/IBM/mathlib/driver/common/big.go index b25fb2cf2ed..5eaf9f3f667 100644 --- a/vendor/github.com/IBM/mathlib/driver/common/big.go +++ b/vendor/github.com/IBM/mathlib/driver/common/big.go @@ -6,16 +6,27 @@ SPDX-License-Identifier: Apache-2.0 package common -import "math/big" +import ( + "math/big" -var onebytes = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} + "github.com/IBM/mathlib/driver" +) + +var onebytes = []byte{ + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, +} var onebig = new(big.Int).SetBytes(onebytes) +const ScalarByteSize = 32 + func BigToBytes(bi *big.Int) []byte { b := bi.Bytes() if bi.Sign() >= 0 { - return append(make([]byte, 32-len(b)), b...) + return append(make([]byte, ScalarByteSize-len(b)), b...) } twoscomp := new(big.Int).Set(onebig) @@ -23,5 +34,80 @@ func BigToBytes(bi *big.Int) []byte { twoscomp = twoscomp.Sub(twoscomp, pos) twoscomp = twoscomp.Add(twoscomp, big.NewInt(1)) b = twoscomp.Bytes() - return append(onebytes[:32-len(b)], b...) + return append(onebytes[:ScalarByteSize-len(b)], b...) +} + +type BaseZr struct { + big.Int + Modulus big.Int +} + +func (b *BaseZr) Plus(a driver.Zr) driver.Zr { + rv := &BaseZr{Modulus: b.Modulus} + rv.Add(&b.Int, &a.(*BaseZr).Int) + return rv +} + +func (b *BaseZr) Minus(a driver.Zr) driver.Zr { + rv := &BaseZr{Modulus: b.Modulus} + rv.Sub(&b.Int, &a.(*BaseZr).Int) + return rv +} + +func (b *BaseZr) Mul(a driver.Zr) driver.Zr { + rv := &BaseZr{Modulus: b.Modulus} + rv.Int.Mul(&b.Int, &a.(*BaseZr).Int) + rv.Int.Mod(&rv.Int, &b.Modulus) + return rv +} + +func (b *BaseZr) PowMod(x driver.Zr) driver.Zr { + rv := &BaseZr{Modulus: b.Modulus} + rv.Exp(&b.Int, &x.(*BaseZr).Int, &b.Modulus) + return rv +} + +func (b *BaseZr) Mod(a driver.Zr) { + b.Int.Mod(&b.Int, &a.(*BaseZr).Int) +} + +func (b *BaseZr) InvModP(p driver.Zr) { + b.Int.ModInverse(&b.Int, &p.(*BaseZr).Int) +} + +func (b *BaseZr) Bytes() []byte { + target := b.Int + + if b.Int.Sign() < 0 || b.Int.Cmp(&b.Modulus) > 0 { + target = *new(big.Int).Set(&b.Int) + target = *target.Mod(&target, &b.Modulus) + if target.Sign() < 0 { + target = *target.Add(&target, &b.Modulus) + } + } + + return BigToBytes(&target) +} + +func (b *BaseZr) Equals(p driver.Zr) bool { + return b.Int.Cmp(&p.(*BaseZr).Int) == 0 +} + +func (b *BaseZr) Copy() driver.Zr { + rv := &BaseZr{Modulus: b.Modulus} + rv.Set(&b.Int) + return rv +} + +func (b *BaseZr) Clone(a driver.Zr) { + raw := a.(*BaseZr).Int.Bytes() + b.Int.SetBytes(raw) +} + +func (b *BaseZr) String() string { + return b.Int.Text(16) +} + +func (b *BaseZr) Neg() { + b.Int.Neg(&b.Int) } diff --git a/vendor/github.com/IBM/mathlib/driver/common/curve.go b/vendor/github.com/IBM/mathlib/driver/common/curve.go new file mode 100644 index 00000000000..79cd10eeb7c --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/common/curve.go @@ -0,0 +1,86 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package common + +import ( + "crypto/rand" + "crypto/sha256" + "io" + "math/big" + + "github.com/IBM/mathlib/driver" +) + +type CurveBase struct { + Modulus big.Int +} + +func (c *CurveBase) ModNeg(a1, m driver.Zr) driver.Zr { + res := &BaseZr{Modulus: c.Modulus} + res.Int.Sub(&m.(*BaseZr).Int, &a1.(*BaseZr).Int) + res.Int.Mod(&res.Int, &m.(*BaseZr).Int) + + return res +} + +func (c *CurveBase) ModMul(a1, b1, m driver.Zr) driver.Zr { + res := &BaseZr{Modulus: c.Modulus} + res.Int.Mul(&a1.(*BaseZr).Int, &b1.(*BaseZr).Int) + res.Int.Mod(&res.Int, &m.(*BaseZr).Int) + + return res +} + +func (c *CurveBase) ModSub(a1, b1, m driver.Zr) driver.Zr { + res := &BaseZr{Modulus: c.Modulus} + res.Int.Sub(&a1.(*BaseZr).Int, &b1.(*BaseZr).Int) + res.Int.Mod(&res.Int, &m.(*BaseZr).Int) + + return res +} + +func (c *CurveBase) ModAdd(a1, b1, m driver.Zr) driver.Zr { + res := &BaseZr{Modulus: c.Modulus} + res.Int.Add(&a1.(*BaseZr).Int, &b1.(*BaseZr).Int) + res.Int.Mod(&res.Int, &m.(*BaseZr).Int) + + return res +} + +func (c *CurveBase) GroupOrder() driver.Zr { + return &BaseZr{Int: c.Modulus, Modulus: c.Modulus} +} + +func (c *CurveBase) NewZrFromBytes(b []byte) driver.Zr { + res := &BaseZr{Modulus: c.Modulus} + res.Int.SetBytes(b) + return res +} + +func (c *CurveBase) NewZrFromInt(i int64) driver.Zr { + return &BaseZr{Int: *big.NewInt(i), Modulus: c.Modulus} +} + +func (c *CurveBase) NewRandomZr(rng io.Reader) driver.Zr { + bi, err := rand.Int(rng, &c.Modulus) + if err != nil { + panic(err) + } + + return &BaseZr{Int: *bi, Modulus: c.Modulus} +} + +func (c *CurveBase) HashToZr(data []byte) driver.Zr { + digest := sha256.Sum256(data) + digestBig := new(big.Int).SetBytes(digest[:]) + digestBig.Mod(digestBig, &c.Modulus) + return &BaseZr{Int: *digestBig, Modulus: c.Modulus} +} + +func (p *CurveBase) Rand() (io.Reader, error) { + return rand.Reader, nil +} diff --git a/vendor/github.com/IBM/mathlib/driver/gurvy/bls12-377.go b/vendor/github.com/IBM/mathlib/driver/gurvy/bls12-377.go new file mode 100644 index 00000000000..c305cc528f5 --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/gurvy/bls12-377.go @@ -0,0 +1,368 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package gurvy + +import ( + "fmt" + "strings" + + "github.com/IBM/mathlib/driver" + "github.com/IBM/mathlib/driver/common" + bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +/*********************************************************************/ + +type bls12377G1 struct { + bls12377.G1Affine +} + +func (g *bls12377G1) Clone(a driver.G1) { + raw := a.(*bls12377G1).G1Affine.Bytes() + _, err := g.SetBytes(raw[:]) + if err != nil { + panic("could not copy point") + } +} + +func (e *bls12377G1) Copy() driver.G1 { + c := &bls12377G1{} + c.Set(&e.G1Affine) + return c +} + +func (g *bls12377G1) Add(a driver.G1) { + j := bls12377.G1Jac{} + j.FromAffine(&g.G1Affine) + j.AddMixed((*bls12377.G1Affine)(&a.(*bls12377G1).G1Affine)) + g.G1Affine.FromJacobian(&j) +} + +func (g *bls12377G1) Mul(a driver.Zr) driver.G1 { + ret := &bls12377G1{} + ret.G1Affine.ScalarMultiplication(&g.G1Affine, &a.(*common.BaseZr).Int) + + return ret +} + +func (g *bls12377G1) Mul2(e driver.Zr, Q driver.G1, f driver.Zr) driver.G1 { + a := g.Mul(e) + b := Q.Mul(f) + a.Add(b) + + return a +} + +func (g *bls12377G1) Equals(a driver.G1) bool { + return g.G1Affine.Equal(&a.(*bls12377G1).G1Affine) +} + +func (g *bls12377G1) Bytes() []byte { + raw := g.G1Affine.RawBytes() + return raw[:] +} + +func (g *bls12377G1) Compressed() []byte { + raw := g.G1Affine.Bytes() + return raw[:] +} + +func (g *bls12377G1) Sub(a driver.G1) { + j, k := bls12377.G1Jac{}, bls12377.G1Jac{} + j.FromAffine(&g.G1Affine) + k.FromAffine(&a.(*bls12377G1).G1Affine) + j.SubAssign(&k) + g.G1Affine.FromJacobian(&j) +} + +func (g *bls12377G1) IsInfinity() bool { + return g.G1Affine.IsInfinity() +} + +func (g *bls12377G1) String() string { + rawstr := g.G1Affine.String() + m := g1StrRegexp.FindAllStringSubmatch(rawstr, -1) + return "(" + strings.TrimLeft(m[0][1], "0") + "," + strings.TrimLeft(m[0][2], "0") + ")" +} + +func (g *bls12377G1) Neg() { + g.G1Affine.Neg(&g.G1Affine) +} + +/*********************************************************************/ + +type bls12377G2 struct { + bls12377.G2Affine +} + +func (g *bls12377G2) Clone(a driver.G2) { + raw := a.(*bls12377G2).G2Affine.Bytes() + _, err := g.SetBytes(raw[:]) + if err != nil { + panic("could not copy point") + } +} + +func (e *bls12377G2) Copy() driver.G2 { + c := &bls12377G2{} + c.Set(&e.G2Affine) + return c +} + +func (g *bls12377G2) Mul(a driver.Zr) driver.G2 { + gc := &bls12377G2{} + gc.G2Affine.ScalarMultiplication(&g.G2Affine, &a.(*common.BaseZr).Int) + + return gc +} + +func (g *bls12377G2) Add(a driver.G2) { + j := bls12377.G2Jac{} + j.FromAffine(&g.G2Affine) + j.AddMixed((*bls12377.G2Affine)(&a.(*bls12377G2).G2Affine)) + g.G2Affine.FromJacobian(&j) +} + +func (g *bls12377G2) Sub(a driver.G2) { + j := bls12377.G2Jac{} + j.FromAffine(&g.G2Affine) + aJac := bls12377.G2Jac{} + aJac.FromAffine((*bls12377.G2Affine)(&a.(*bls12377G2).G2Affine)) + j.SubAssign(&aJac) + g.G2Affine.FromJacobian(&j) +} + +func (g *bls12377G2) Affine() { + // we're always affine +} + +func (g *bls12377G2) Bytes() []byte { + raw := g.G2Affine.RawBytes() + return raw[:] +} + +func (g *bls12377G2) Compressed() []byte { + raw := g.G2Affine.Bytes() + return raw[:] +} + +func (g *bls12377G2) String() string { + return g.G2Affine.String() +} + +func (g *bls12377G2) Equals(a driver.G2) bool { + return g.G2Affine.Equal(&a.(*bls12377G2).G2Affine) +} + +/*********************************************************************/ + +type bls12377Gt struct { + bls12377.GT +} + +func (g *bls12377Gt) Exp(x driver.Zr) driver.Gt { + copy := bls12377.GT{} + return &bls12377Gt{*copy.Exp(g.GT, &x.(*common.BaseZr).Int)} +} + +func (g *bls12377Gt) Equals(a driver.Gt) bool { + return g.GT.Equal(&a.(*bls12377Gt).GT) +} + +func (g *bls12377Gt) Inverse() { + g.GT.Inverse(&g.GT) +} + +func (g *bls12377Gt) Mul(a driver.Gt) { + g.GT.Mul(&g.GT, &a.(*bls12377Gt).GT) +} + +func (g *bls12377Gt) IsUnity() bool { + unity := bls12377.GT{} + unity.SetOne() + + return unity.Equal(&g.GT) +} + +func (g *bls12377Gt) ToString() string { + return g.GT.String() +} + +func (g *bls12377Gt) Bytes() []byte { + raw := g.GT.Bytes() + return raw[:] +} + +/*********************************************************************/ + +func NewBls12_377() *Bls12_377 { + return &Bls12_377{common.CurveBase{Modulus: *fr.Modulus()}} +} + +type Bls12_377 struct { + common.CurveBase +} + +func (c *Bls12_377) Pairing(p2 driver.G2, p1 driver.G1) driver.Gt { + t, err := bls12377.MillerLoop([]bls12377.G1Affine{p1.(*bls12377G1).G1Affine}, []bls12377.G2Affine{p2.(*bls12377G2).G2Affine}) + if err != nil { + panic(fmt.Sprintf("pairing failed [%s]", err.Error())) + } + + return &bls12377Gt{t} +} + +func (c *Bls12_377) Pairing2(p2a, p2b driver.G2, p1a, p1b driver.G1) driver.Gt { + t, err := bls12377.MillerLoop([]bls12377.G1Affine{p1a.(*bls12377G1).G1Affine, p1b.(*bls12377G1).G1Affine}, []bls12377.G2Affine{p2a.(*bls12377G2).G2Affine, p2b.(*bls12377G2).G2Affine}) + if err != nil { + panic(fmt.Sprintf("pairing 2 failed [%s]", err.Error())) + } + + return &bls12377Gt{t} +} + +func (c *Bls12_377) FExp(a driver.Gt) driver.Gt { + return &bls12377Gt{bls12377.FinalExponentiation(&a.(*bls12377Gt).GT)} +} + +var g1Bytes12_377 [48]byte +var g2Bytes12_377 [96]byte + +func init() { + _, _, g1, g2 := bls12377.Generators() + g1Bytes12_377 = g1.Bytes() + g2Bytes12_377 = g2.Bytes() +} + +func (c *Bls12_377) GenG1() driver.G1 { + r := &bls12377G1{} + _, err := r.SetBytes(g1Bytes12_377[:]) + if err != nil { + panic("could not generate point") + } + + return r +} + +func (c *Bls12_377) GenG2() driver.G2 { + r := &bls12377G2{} + _, err := r.SetBytes(g2Bytes12_377[:]) + if err != nil { + panic("could not generate point") + } + + return r +} + +func (c *Bls12_377) GenGt() driver.Gt { + g1 := c.GenG1() + g2 := c.GenG2() + gengt := c.Pairing(g2, g1) + gengt = c.FExp(gengt) + return gengt +} + +func (c *Bls12_377) CoordinateByteSize() int { + return bls12377.SizeOfG1AffineCompressed +} + +func (c *Bls12_377) G1ByteSize() int { + return bls12377.SizeOfG1AffineUncompressed +} + +func (c *Bls12_377) CompressedG1ByteSize() int { + return bls12377.SizeOfG1AffineCompressed +} + +func (c *Bls12_377) G2ByteSize() int { + return bls12377.SizeOfG2AffineUncompressed +} + +func (c *Bls12_377) CompressedG2ByteSize() int { + return bls12377.SizeOfG2AffineCompressed +} + +func (c *Bls12_377) ScalarByteSize() int { + return common.ScalarByteSize +} + +func (c *Bls12_377) NewG1() driver.G1 { + return &bls12377G1{} +} + +func (c *Bls12_377) NewG2() driver.G2 { + return &bls12377G2{} +} + +func (c *Bls12_377) NewG1FromBytes(b []byte) driver.G1 { + v := &bls12377G1{} + _, err := v.G1Affine.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_377) NewG2FromBytes(b []byte) driver.G2 { + v := &bls12377G2{} + _, err := v.G2Affine.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_377) NewG1FromCompressed(b []byte) driver.G1 { + v := &bls12377G1{} + _, err := v.G1Affine.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_377) NewG2FromCompressed(b []byte) driver.G2 { + v := &bls12377G2{} + _, err := v.G2Affine.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_377) NewGtFromBytes(b []byte) driver.Gt { + v := &bls12377Gt{} + err := v.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_377) HashToG1(data []byte) driver.G1 { + g1, err := bls12377.HashToG1(data, []byte{}) + if err != nil { + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + } + + return &bls12377G1{g1} +} + +func (p *Bls12_377) HashToG1WithDomain(data, domain []byte) driver.G1 { + g1, err := bls12377.HashToG1(data, domain) + if err != nil { + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + } + + return &bls12377G1{g1} +} diff --git a/vendor/github.com/IBM/mathlib/driver/gurvy/bls12-381.go b/vendor/github.com/IBM/mathlib/driver/gurvy/bls12-381.go new file mode 100644 index 00000000000..48e49b47704 --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/gurvy/bls12-381.go @@ -0,0 +1,408 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package gurvy + +import ( + "fmt" + "hash" + "strings" + + "github.com/IBM/mathlib/driver" + "github.com/IBM/mathlib/driver/common" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "golang.org/x/crypto/blake2b" +) + +/*********************************************************************/ + +type bls12381G1 struct { + bls12381.G1Affine +} + +func (g *bls12381G1) Clone(a driver.G1) { + raw := a.(*bls12381G1).G1Affine.Bytes() + _, err := g.SetBytes(raw[:]) + if err != nil { + panic("could not copy point") + } +} + +func (e *bls12381G1) Copy() driver.G1 { + c := &bls12381G1{} + c.Set(&e.G1Affine) + return c +} + +func (g *bls12381G1) Add(a driver.G1) { + j := bls12381.G1Jac{} + j.FromAffine(&g.G1Affine) + j.AddMixed((*bls12381.G1Affine)(&a.(*bls12381G1).G1Affine)) + g.G1Affine.FromJacobian(&j) +} + +func (g *bls12381G1) Mul(a driver.Zr) driver.G1 { + gc := &bls12381G1{} + gc.G1Affine.ScalarMultiplication(&g.G1Affine, &a.(*common.BaseZr).Int) + + return gc +} + +func (g *bls12381G1) Mul2(e driver.Zr, Q driver.G1, f driver.Zr) driver.G1 { + a := g.Mul(e) + b := Q.Mul(f) + a.Add(b) + + return a +} + +func (g *bls12381G1) Equals(a driver.G1) bool { + return g.G1Affine.Equal(&a.(*bls12381G1).G1Affine) +} + +func (g *bls12381G1) Bytes() []byte { + raw := g.G1Affine.RawBytes() + return raw[:] +} + +func (g *bls12381G1) Compressed() []byte { + raw := g.G1Affine.Bytes() + return raw[:] +} + +func (g *bls12381G1) Sub(a driver.G1) { + j, k := bls12381.G1Jac{}, bls12381.G1Jac{} + j.FromAffine(&g.G1Affine) + k.FromAffine(&a.(*bls12381G1).G1Affine) + j.SubAssign(&k) + g.G1Affine.FromJacobian(&j) +} + +func (g *bls12381G1) IsInfinity() bool { + return g.G1Affine.IsInfinity() +} + +func (g *bls12381G1) String() string { + rawstr := g.G1Affine.String() + m := g1StrRegexp.FindAllStringSubmatch(rawstr, -1) + return "(" + strings.TrimLeft(m[0][1], "0") + "," + strings.TrimLeft(m[0][2], "0") + ")" +} + +func (g *bls12381G1) Neg() { + g.G1Affine.Neg(&g.G1Affine) +} + +/*********************************************************************/ + +type bls12381G2 struct { + bls12381.G2Affine +} + +func (g *bls12381G2) Clone(a driver.G2) { + raw := a.(*bls12381G2).G2Affine.Bytes() + _, err := g.SetBytes(raw[:]) + if err != nil { + panic("could not copy point") + } +} + +func (e *bls12381G2) Copy() driver.G2 { + c := &bls12381G2{} + c.Set(&e.G2Affine) + return c +} + +func (g *bls12381G2) Mul(a driver.Zr) driver.G2 { + gc := &bls12381G2{} + gc.G2Affine.ScalarMultiplication(&g.G2Affine, &a.(*common.BaseZr).Int) + + return gc +} + +func (g *bls12381G2) Add(a driver.G2) { + j := bls12381.G2Jac{} + j.FromAffine(&g.G2Affine) + j.AddMixed((*bls12381.G2Affine)(&a.(*bls12381G2).G2Affine)) + g.G2Affine.FromJacobian(&j) +} + +func (g *bls12381G2) Sub(a driver.G2) { + j := bls12381.G2Jac{} + j.FromAffine(&g.G2Affine) + aJac := bls12381.G2Jac{} + aJac.FromAffine((*bls12381.G2Affine)(&a.(*bls12381G2).G2Affine)) + j.SubAssign(&aJac) + g.G2Affine.FromJacobian(&j) +} + +func (g *bls12381G2) Affine() { + // we're always affine +} + +func (g *bls12381G2) Bytes() []byte { + raw := g.G2Affine.RawBytes() + return raw[:] +} + +func (g *bls12381G2) Compressed() []byte { + raw := g.G2Affine.Bytes() + return raw[:] +} + +func (g *bls12381G2) String() string { + return g.G2Affine.String() +} + +func (g *bls12381G2) Equals(a driver.G2) bool { + return g.G2Affine.Equal(&a.(*bls12381G2).G2Affine) +} + +/*********************************************************************/ + +type bls12381Gt struct { + bls12381.GT +} + +func (g *bls12381Gt) Exp(x driver.Zr) driver.Gt { + copy := bls12381.GT{} + return &bls12381Gt{*copy.Exp(g.GT, &x.(*common.BaseZr).Int)} +} + +func (g *bls12381Gt) Equals(a driver.Gt) bool { + return g.GT.Equal(&a.(*bls12381Gt).GT) +} + +func (g *bls12381Gt) Inverse() { + g.GT.Inverse(&g.GT) +} + +func (g *bls12381Gt) Mul(a driver.Gt) { + g.GT.Mul(&g.GT, &a.(*bls12381Gt).GT) +} + +func (g *bls12381Gt) IsUnity() bool { + unity := bls12381.GT{} + unity.SetOne() + + return unity.Equal(&g.GT) +} + +func (g *bls12381Gt) ToString() string { + return g.GT.String() +} + +func (g *bls12381Gt) Bytes() []byte { + raw := g.GT.Bytes() + return raw[:] +} + +/*********************************************************************/ + +func NewBls12_381() *Bls12_381 { + return &Bls12_381{common.CurveBase{Modulus: *fr.Modulus()}} +} + +func NewBls12_381BBS() *Bls12_381BBS { + return &Bls12_381BBS{*NewBls12_381()} +} + +type Bls12_381 struct { + common.CurveBase +} + +type Bls12_381BBS struct { + Bls12_381 +} + +func (c *Bls12_381) Pairing(p2 driver.G2, p1 driver.G1) driver.Gt { + t, err := bls12381.MillerLoop([]bls12381.G1Affine{p1.(*bls12381G1).G1Affine}, []bls12381.G2Affine{p2.(*bls12381G2).G2Affine}) + if err != nil { + panic(fmt.Sprintf("pairing failed [%s]", err.Error())) + } + + return &bls12381Gt{t} +} + +func (c *Bls12_381) Pairing2(p2a, p2b driver.G2, p1a, p1b driver.G1) driver.Gt { + t, err := bls12381.MillerLoop([]bls12381.G1Affine{p1a.(*bls12381G1).G1Affine, p1b.(*bls12381G1).G1Affine}, []bls12381.G2Affine{p2a.(*bls12381G2).G2Affine, p2b.(*bls12381G2).G2Affine}) + if err != nil { + panic(fmt.Sprintf("pairing 2 failed [%s]", err.Error())) + } + + return &bls12381Gt{t} +} + +func (c *Bls12_381) FExp(a driver.Gt) driver.Gt { + return &bls12381Gt{bls12381.FinalExponentiation(&a.(*bls12381Gt).GT)} +} + +var g1Bytes12_381 [48]byte +var g2Bytes12_381 [96]byte + +func init() { + _, _, g1, g2 := bls12381.Generators() + g1Bytes12_381 = g1.Bytes() + g2Bytes12_381 = g2.Bytes() +} + +func (c *Bls12_381) GenG1() driver.G1 { + r := &bls12381G1{} + _, err := r.SetBytes(g1Bytes12_381[:]) + if err != nil { + panic("could not generate point") + } + + return r +} + +func (c *Bls12_381) GenG2() driver.G2 { + r := &bls12381G2{} + _, err := r.SetBytes(g2Bytes12_381[:]) + if err != nil { + panic("could not generate point") + } + + return r +} + +func (c *Bls12_381) GenGt() driver.Gt { + g1 := c.GenG1() + g2 := c.GenG2() + gengt := c.Pairing(g2, g1) + gengt = c.FExp(gengt) + return gengt +} + +func (c *Bls12_381) CoordinateByteSize() int { + return bls12381.SizeOfG1AffineCompressed +} + +func (c *Bls12_381) G1ByteSize() int { + return bls12381.SizeOfG1AffineUncompressed +} + +func (c *Bls12_381) CompressedG1ByteSize() int { + return bls12381.SizeOfG1AffineCompressed +} + +func (c *Bls12_381) G2ByteSize() int { + return bls12381.SizeOfG2AffineUncompressed +} + +func (c *Bls12_381) CompressedG2ByteSize() int { + return bls12381.SizeOfG2AffineCompressed +} + +func (c *Bls12_381) ScalarByteSize() int { + return common.ScalarByteSize +} + +func (c *Bls12_381) NewG1() driver.G1 { + return &bls12381G1{} +} + +func (c *Bls12_381) NewG2() driver.G2 { + return &bls12381G2{} +} + +func (c *Bls12_381) NewG1FromBytes(b []byte) driver.G1 { + v := &bls12381G1{} + _, err := v.G1Affine.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_381) NewG2FromBytes(b []byte) driver.G2 { + v := &bls12381G2{} + _, err := v.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_381) NewG1FromCompressed(b []byte) driver.G1 { + v := &bls12381G1{} + _, err := v.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_381) NewG2FromCompressed(b []byte) driver.G2 { + v := &bls12381G2{} + _, err := v.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_381) NewGtFromBytes(b []byte) driver.Gt { + v := &bls12381Gt{} + err := v.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v +} + +func (c *Bls12_381) HashToG1(data []byte) driver.G1 { + g1, err := bls12381.HashToG1(data, []byte{}) + if err != nil { + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + } + + return &bls12381G1{g1} +} + +func (p *Bls12_381) HashToG1WithDomain(data, domain []byte) driver.G1 { + g1, err := bls12381.HashToG1(data, domain) + if err != nil { + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + } + + return &bls12381G1{g1} +} + +func (c *Bls12_381BBS) HashToG1(data []byte) driver.G1 { + hashFunc := func() hash.Hash { + // We pass a null key so error is impossible here. + h, _ := blake2b.New512(nil) //nolint:errcheck + return h + } + + g1, err := HashToG1GenericBESwu(data, []byte{}, hashFunc) + if err != nil { + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + } + + return &bls12381G1{g1} +} + +func (p *Bls12_381BBS) HashToG1WithDomain(data, domain []byte) driver.G1 { + hashFunc := func() hash.Hash { + // We pass a null key so error is impossible here. + h, _ := blake2b.New512(nil) //nolint:errcheck + return h + } + + g1, err := HashToG1GenericBESwu(data, domain, hashFunc) + if err != nil { + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + } + + return &bls12381G1{g1} +} diff --git a/vendor/github.com/IBM/mathlib/driver/gurvy/bn254.go b/vendor/github.com/IBM/mathlib/driver/gurvy/bn254.go index 8d2d1d713fd..a37c5b4cc5b 100644 --- a/vendor/github.com/IBM/mathlib/driver/gurvy/bn254.go +++ b/vendor/github.com/IBM/mathlib/driver/gurvy/bn254.go @@ -7,11 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package gurvy import ( - "crypto/rand" - "crypto/sha256" "fmt" - "io" - "math/big" "regexp" "strings" @@ -23,51 +19,8 @@ import ( /*********************************************************************/ -type bn254Zr struct { - *big.Int -} - -func (z *bn254Zr) Plus(a driver.Zr) driver.Zr { - return &bn254Zr{new(big.Int).Add(z.Int, a.(*bn254Zr).Int)} -} - -func (z *bn254Zr) Mod(a driver.Zr) { - z.Int.Mod(z.Int, a.(*bn254Zr).Int) -} - -func (z *bn254Zr) PowMod(x driver.Zr) driver.Zr { - return &bn254Zr{new(big.Int).Exp(z.Int, x.(*bn254Zr).Int, fr.Modulus())} -} - -func (z *bn254Zr) InvModP(a driver.Zr) { - z.Int.ModInverse(z.Int, a.(*bn254Zr).Int) -} - -func (z *bn254Zr) Bytes() []byte { - return common.BigToBytes(z.Int) -} - -func (z *bn254Zr) Equals(a driver.Zr) bool { - return z.Int.Cmp(a.(*bn254Zr).Int) == 0 -} - -func (z *bn254Zr) Copy() driver.Zr { - return &bn254Zr{new(big.Int).Set(z.Int)} -} - -func (z *bn254Zr) Clone(a driver.Zr) { - raw := a.(*bn254Zr).Int.Bytes() - z.Int.SetBytes(raw) -} - -func (z *bn254Zr) String() string { - return z.Int.Text(16) -} - -/*********************************************************************/ - type bn254G1 struct { - *bn254.G1Affine + bn254.G1Affine } func (g *bn254G1) Clone(a driver.G1) { @@ -79,24 +32,23 @@ func (g *bn254G1) Clone(a driver.G1) { } func (e *bn254G1) Copy() driver.G1 { - c := &bn254.G1Affine{} - c.Set(e.G1Affine) - return &bn254G1{c} + c := &bn254G1{} + c.Set(&e.G1Affine) + return c } func (g *bn254G1) Add(a driver.G1) { - j := &bn254.G1Jac{} - j.FromAffine(g.G1Affine) - j.AddMixed((*bn254.G1Affine)(a.(*bn254G1).G1Affine)) - g.G1Affine.FromJacobian(j) + j := bn254.G1Jac{} + j.FromAffine(&g.G1Affine) + j.AddMixed((*bn254.G1Affine)(&a.(*bn254G1).G1Affine)) + g.G1Affine.FromJacobian(&j) } func (g *bn254G1) Mul(a driver.Zr) driver.G1 { - gc := &bn254G1{&bn254.G1Affine{}} - gc.Clone(g) - gc.G1Affine.ScalarMultiplication(g.G1Affine, a.(*bn254Zr).Int) + res := &bn254G1{} + res.G1Affine.ScalarMultiplication(&g.G1Affine, &a.(*common.BaseZr).Int) - return gc + return res } func (g *bn254G1) Mul2(e driver.Zr, Q driver.G1, f driver.Zr) driver.G1 { @@ -108,7 +60,7 @@ func (g *bn254G1) Mul2(e driver.Zr, Q driver.G1, f driver.Zr) driver.G1 { } func (g *bn254G1) Equals(a driver.G1) bool { - return g.G1Affine.Equal(a.(*bn254G1).G1Affine) + return g.G1Affine.Equal(&a.(*bn254G1).G1Affine) } func (g *bn254G1) Bytes() []byte { @@ -116,19 +68,24 @@ func (g *bn254G1) Bytes() []byte { return raw[:] } +func (g *bn254G1) Compressed() []byte { + raw := g.G1Affine.Bytes() + return raw[:] +} + func (g *bn254G1) Sub(a driver.G1) { - j, k := &bn254.G1Jac{}, &bn254.G1Jac{} - j.FromAffine(g.G1Affine) - k.FromAffine(a.(*bn254G1).G1Affine) - j.SubAssign(k) - g.G1Affine.FromJacobian(j) + j, k := bn254.G1Jac{}, bn254.G1Jac{} + j.FromAffine(&g.G1Affine) + k.FromAffine(&a.(*bn254G1).G1Affine) + j.SubAssign(&k) + g.G1Affine.FromJacobian(&j) } func (g *bn254G1) IsInfinity() bool { return g.G1Affine.IsInfinity() } -var g1StrRegexp *regexp.Regexp = regexp.MustCompile(`^E\([[]([0-9]+),([0-9]+)[]]\),$`) +var g1StrRegexp *regexp.Regexp = regexp.MustCompile(`^E\([[]([0-9]+),([0-9]+)[]]\)$`) func (g *bn254G1) String() string { rawstr := g.G1Affine.String() @@ -136,10 +93,14 @@ func (g *bn254G1) String() string { return "(" + strings.TrimLeft(m[0][1], "0") + "," + strings.TrimLeft(m[0][2], "0") + ")" } +func (g *bn254G1) Neg() { + g.G1Affine.Neg(&g.G1Affine) +} + /*********************************************************************/ type bn254G2 struct { - *bn254.G2Affine + bn254.G2Affine } func (g *bn254G2) Clone(a driver.G2) { @@ -151,33 +112,32 @@ func (g *bn254G2) Clone(a driver.G2) { } func (e *bn254G2) Copy() driver.G2 { - c := &bn254.G2Affine{} - c.Set(e.G2Affine) - return &bn254G2{c} + c := &bn254G2{} + c.Set(&e.G2Affine) + return c } func (g *bn254G2) Mul(a driver.Zr) driver.G2 { - gc := &bn254G2{&bn254.G2Affine{}} - gc.Clone(g) - gc.G2Affine.ScalarMultiplication(g.G2Affine, a.(*bn254Zr).Int) + gc := &bn254G2{} + gc.G2Affine.ScalarMultiplication(&g.G2Affine, &a.(*common.BaseZr).Int) return gc } func (g *bn254G2) Add(a driver.G2) { - j := &bn254.G2Jac{} - j.FromAffine(g.G2Affine) - j.AddMixed((*bn254.G2Affine)(a.(*bn254G2).G2Affine)) - g.G2Affine.FromJacobian(j) + j := bn254.G2Jac{} + j.FromAffine(&g.G2Affine) + j.AddMixed((*bn254.G2Affine)(&a.(*bn254G2).G2Affine)) + g.G2Affine.FromJacobian(&j) } func (g *bn254G2) Sub(a driver.G2) { - j := &bn254.G2Jac{} - j.FromAffine(g.G2Affine) - aJac := &bn254.G2Jac{} - aJac.FromAffine((*bn254.G2Affine)(a.(*bn254G2).G2Affine)) - j.SubAssign(aJac) - g.G2Affine.FromJacobian(j) + j := bn254.G2Jac{} + j.FromAffine(&g.G2Affine) + aJac := bn254.G2Jac{} + aJac.FromAffine((*bn254.G2Affine)(&a.(*bn254G2).G2Affine)) + j.SubAssign(&aJac) + g.G2Affine.FromJacobian(&j) } func (g *bn254G2) Affine() { @@ -189,37 +149,47 @@ func (g *bn254G2) Bytes() []byte { return raw[:] } +func (g *bn254G2) Compressed() []byte { + raw := g.G2Affine.Bytes() + return raw[:] +} + func (g *bn254G2) String() string { return g.G2Affine.String() } func (g *bn254G2) Equals(a driver.G2) bool { - return g.G2Affine.Equal(a.(*bn254G2).G2Affine) + return g.G2Affine.Equal(&a.(*bn254G2).G2Affine) } /*********************************************************************/ type bn254Gt struct { - *bn254.GT + bn254.GT +} + +func (g *bn254Gt) Exp(x driver.Zr) driver.Gt { + copy := bn254.GT{} + return &bn254Gt{*copy.Exp(g.GT, &x.(*common.BaseZr).Int)} } func (g *bn254Gt) Equals(a driver.Gt) bool { - return g.GT.Equal(a.(*bn254Gt).GT) + return g.GT.Equal(&a.(*bn254Gt).GT) } func (g *bn254Gt) Inverse() { - g.GT.Inverse(g.GT) + g.GT.Inverse(&g.GT) } func (g *bn254Gt) Mul(a driver.Gt) { - g.GT.Mul(g.GT, a.(*bn254Gt).GT) + g.GT.Mul(&g.GT, &a.(*bn254Gt).GT) } func (g *bn254Gt) IsUnity() bool { - unity := &bn254.GT{} + unity := bn254.GT{} unity.SetOne() - return unity.Equal(g.GT) + return unity.Equal(&g.GT) } func (g *bn254Gt) ToString() string { @@ -233,80 +203,63 @@ func (g *bn254Gt) Bytes() []byte { /*********************************************************************/ +func NewBn254() *Bn254 { + return &Bn254{common.CurveBase{Modulus: *fr.Modulus()}} +} + type Bn254 struct { + common.CurveBase } func (c *Bn254) Pairing(p2 driver.G2, p1 driver.G1) driver.Gt { - t, err := bn254.MillerLoop([]bn254.G1Affine{*p1.(*bn254G1).G1Affine}, []bn254.G2Affine{*p2.(*bn254G2).G2Affine}) + t, err := bn254.MillerLoop([]bn254.G1Affine{p1.(*bn254G1).G1Affine}, []bn254.G2Affine{p2.(*bn254G2).G2Affine}) if err != nil { panic(fmt.Sprintf("pairing failed [%s]", err.Error())) } - return &bn254Gt{&t} + return &bn254Gt{t} } func (c *Bn254) Pairing2(p2a, p2b driver.G2, p1a, p1b driver.G1) driver.Gt { - t, err := bn254.MillerLoop([]bn254.G1Affine{*p1a.(*bn254G1).G1Affine, *p1b.(*bn254G1).G1Affine}, []bn254.G2Affine{*p2a.(*bn254G2).G2Affine, *p2b.(*bn254G2).G2Affine}) + t, err := bn254.MillerLoop([]bn254.G1Affine{p1a.(*bn254G1).G1Affine, p1b.(*bn254G1).G1Affine}, []bn254.G2Affine{p2a.(*bn254G2).G2Affine, p2b.(*bn254G2).G2Affine}) if err != nil { panic(fmt.Sprintf("pairing 2 failed [%s]", err.Error())) } - return &bn254Gt{&t} + return &bn254Gt{t} } func (c *Bn254) FExp(a driver.Gt) driver.Gt { - gt := bn254.FinalExponentiation(a.(*bn254Gt).GT) - return &bn254Gt{>} + return &bn254Gt{bn254.FinalExponentiation(&a.(*bn254Gt).GT)} } -func (*Bn254) ModAdd(a, b, m driver.Zr) driver.Zr { - c := a.Plus(b) - c.Mod(m) - return c -} +var g1Bytes254 [32]byte +var g2Bytes254 [64]byte -func (c *Bn254) ModSub(a, b, m driver.Zr) driver.Zr { - return c.ModAdd(a, c.ModNeg(b, m), m) -} - -func (c *Bn254) ModNeg(a1, m driver.Zr) driver.Zr { - a := a1.Copy() - a.Mod(m) - return &bn254Zr{a.(*bn254Zr).Int.Sub(m.(*bn254Zr).Int, a.(*bn254Zr).Int)} -} - -func (c *Bn254) ModMul(a1, b1, m driver.Zr) driver.Zr { - a := a1.Copy() - b := b1.Copy() - a.Mod(m) - b.Mod(m) - return &bn254Zr{a.(*bn254Zr).Int.Mul(a.(*bn254Zr).Int, b.(*bn254Zr).Int)} +func init() { + _, _, g1, g2 := bn254.Generators() + g1Bytes254 = g1.Bytes() + g2Bytes254 = g2.Bytes() } func (c *Bn254) GenG1() driver.G1 { - _, _, g1, _ := bn254.Generators() - raw := g1.Bytes() - - r := &bn254.G1Affine{} - _, err := r.SetBytes(raw[:]) + r := &bn254G1{} + _, err := r.SetBytes(g1Bytes254[:]) if err != nil { panic("could not generate point") } - return &bn254G1{r} + return r } func (c *Bn254) GenG2() driver.G2 { - _, _, _, g2 := bn254.Generators() - raw := g2.Bytes() - - r := &bn254.G2Affine{} - _, err := r.SetBytes(raw[:]) + r := &bn254G2{} + _, err := r.SetBytes(g2Bytes254[:]) if err != nil { panic("could not generate point") } - return &bn254G2{r} + return r } func (c *Bn254) GenGt() driver.Gt { @@ -317,91 +270,102 @@ func (c *Bn254) GenGt() driver.Gt { return gengt } -func (c *Bn254) GroupOrder() driver.Zr { - return &bn254Zr{fr.Modulus()} +func (c *Bn254) CoordinateByteSize() int { + return bn254.SizeOfG1AffineCompressed } -func (c *Bn254) FieldBytes() int { - return 32 +func (c *Bn254) G1ByteSize() int { + return bn254.SizeOfG1AffineUncompressed } -func (c *Bn254) NewG1() driver.G1 { - return &bn254G1{&bn254.G1Affine{}} +func (c *Bn254) CompressedG1ByteSize() int { + return bn254.SizeOfG1AffineCompressed } -func (c *Bn254) NewG2() driver.G2 { - return &bn254G2{&bn254.G2Affine{}} +func (c *Bn254) G2ByteSize() int { + return bn254.SizeOfG2AffineUncompressed } -func (c *Bn254) NewG1FromCoords(ix, iy driver.Zr) driver.G1 { - return nil +func (c *Bn254) CompressedG2ByteSize() int { + return bn254.SizeOfG2AffineCompressed } -func (c *Bn254) NewZrFromBytes(b []byte) driver.Zr { - return &bn254Zr{new(big.Int).SetBytes(b)} +func (c *Bn254) ScalarByteSize() int { + return common.ScalarByteSize } -func (c *Bn254) NewZrFromInt(i int64) driver.Zr { - return &bn254Zr{big.NewInt(i)} +func (c *Bn254) NewG1() driver.G1 { + return &bn254G1{} +} + +func (c *Bn254) NewG2() driver.G2 { + return &bn254G2{} } func (c *Bn254) NewG1FromBytes(b []byte) driver.G1 { - v := &bn254.G1Affine{} + v := &bn254G1{} _, err := v.SetBytes(b) if err != nil { panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) } - return &bn254G1{v} + return v } func (c *Bn254) NewG2FromBytes(b []byte) driver.G2 { - v := &bn254.G2Affine{} + v := &bn254G2{} _, err := v.SetBytes(b) if err != nil { panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) } - return &bn254G2{v} + return v } -func (c *Bn254) NewGtFromBytes(b []byte) driver.Gt { - v := &bn254.GT{} - err := v.SetBytes(b) +func (c *Bn254) NewG1FromCompressed(b []byte) driver.G1 { + v := &bn254G1{} + _, err := v.SetBytes(b) if err != nil { panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) } - return &bn254Gt{v} + return v } -func (c *Bn254) HashToZr(data []byte) driver.Zr { - digest := sha256.Sum256(data) - digestBig := c.NewZrFromBytes(digest[:]) - digestBig.Mod(c.GroupOrder()) - return digestBig +func (c *Bn254) NewG2FromCompressed(b []byte) driver.G2 { + v := &bn254G2{} + _, err := v.SetBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return v } -func (c *Bn254) HashToG1(data []byte) driver.G1 { - g1, err := bn254.HashToCurveG1Svdw(data, []byte{}) +func (c *Bn254) NewGtFromBytes(b []byte) driver.Gt { + v := &bn254Gt{} + err := v.SetBytes(b) if err != nil { - panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) } - return &bn254G1{&g1} + return v } -func (c *Bn254) NewRandomZr(rng io.Reader) driver.Zr { - res := new(big.Int) - v := &fr.Element{} - _, err := v.SetRandom() +func (c *Bn254) HashToG1(data []byte) driver.G1 { + g1, err := bn254.HashToG1(data, []byte{}) if err != nil { - panic(err) + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) } - return &bn254Zr{v.ToBigIntRegular(res)} + return &bn254G1{g1} } -func (c *Bn254) Rand() (io.Reader, error) { - return rand.Reader, nil +func (p *Bn254) HashToG1WithDomain(data, domain []byte) driver.G1 { + g1, err := bn254.HashToG1(data, domain) + if err != nil { + panic(fmt.Sprintf("HashToG1 failed [%s]", err.Error())) + } + + return &bn254G1{g1} } diff --git a/vendor/github.com/IBM/mathlib/driver/gurvy/custom.go b/vendor/github.com/IBM/mathlib/driver/gurvy/custom.go new file mode 100644 index 00000000000..713697f7f0d --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/gurvy/custom.go @@ -0,0 +1,191 @@ +/* +Copyright IBM Corp. All Rights Reserved. +Copyright 2020 ConsenSys Software Inc. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package gurvy + +import ( + "errors" + "hash" + "unsafe" + + "github.com/IBM/mathlib/driver/kilic" + bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/field/pool" +) + +const Bits = 381 // number of bits needed to represent a Element + +type Element [6]uint64 + +type G1Affine struct { + X, Y fp.Element +} + +//go:linkname g1Isogeny github.com/consensys/gnark-crypto/ecc/bls12-381.g1Isogeny +func g1Isogeny(p *G1Affine) + +func toKilicElement(p *fp.Element) *kilic.Fe { + return (*kilic.Fe)(unsafe.Pointer(p)) +} + +func toGurvyElement(p *kilic.Fe) *fp.Element { + return (*fp.Element)(unsafe.Pointer(p)) +} + +func toGurvyAffine(p *G1Affine) *bls12381.G1Affine { + return (*bls12381.G1Affine)(unsafe.Pointer(p)) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +// ExpandMsgXmd expands msg to a slice of lenInBytes bytes. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5 +// https://tools.ietf.org/html/rfc8017#section-4.1 (I2OSP/O2ISP) +func ExpandMsgXmd(msg, dst []byte, lenInBytes int, hashFunc func() hash.Hash) ([]byte, error) { + h := hashFunc() + + ell := (lenInBytes + h.Size() - 1) / h.Size() // ceil(len_in_bytes / b_in_bytes) + if ell > 255 { + return nil, errors.New("invalid lenInBytes") + } + if len(dst) > 255 { + return nil, errors.New("invalid domain size (>255 bytes)") + } + sizeDomain := uint8(len(dst)) + + // Z_pad = I2OSP(0, r_in_bytes) + // l_i_b_str = I2OSP(len_in_bytes, 2) + // DST_prime = I2OSP(len(DST), 1) ∥ DST + // b₀ = H(Z_pad ∥ msg ∥ l_i_b_str ∥ I2OSP(0, 1) ∥ DST_prime) + h.Reset() + if _, err := h.Write(make([]byte, h.BlockSize())); err != nil { + return nil, err + } + if _, err := h.Write(msg); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(lenInBytes >> 8), uint8(lenInBytes), uint8(0)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b0 := h.Sum(nil) + + // b₁ = H(b₀ ∥ I2OSP(1, 1) ∥ DST_prime) + h.Reset() + if _, err := h.Write(b0); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(1)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 := h.Sum(nil) + + res := make([]byte, lenInBytes) + copy(res[:h.Size()], b1) + + for i := 2; i <= ell; i++ { + // b_i = H(strxor(b₀, b_(i - 1)) ∥ I2OSP(i, 1) ∥ DST_prime) + h.Reset() + strxor := make([]byte, h.Size()) + for j := 0; j < h.Size(); j++ { + strxor[j] = b0[j] ^ b1[j] + } + if _, err := h.Write(strxor); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(i)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 = h.Sum(nil) + copy(res[h.Size()*(i-1):min(h.Size()*i, len(res))], b1) + } + return res, nil +} + +// Hash msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func Hash(msg, dst []byte, count int, hashFunc func() hash.Hash) ([]fp.Element, error) { + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + const Bytes = 1 + (Bits-1)/8 + const L = 16 + Bytes + + lenInBytes := count * L + pseudoRandomBytes, err := ExpandMsgXmd(msg, dst, lenInBytes, hashFunc) + if err != nil { + return nil, err + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + res := make([]fp.Element, count) + for i := 0; i < count; i++ { + vv.SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + res[i].SetBigInt(vv) + } + + // release object into pool + pool.BigInt.Put(vv) + + return res, nil +} + +func HashToG1GenericBESwu(msg, dst []byte, hashFunc func() hash.Hash) (bls12381.G1Affine, error) { + u, err := Hash(msg, dst, 2*1, hashFunc) + if err != nil { + return bls12381.G1Affine{}, err + } + + xQ0, yQ0 := kilic.SwuMapG1BE(toKilicElement(&u[0])) + xQ1, yQ1 := kilic.SwuMapG1BE(toKilicElement(&u[1])) + + _xq0 := toGurvyElement(xQ0) + _yq0 := toGurvyElement(yQ0) + _xq1 := toGurvyElement(xQ1) + _yq1 := toGurvyElement(yQ1) + + Q0 := G1Affine{*_xq0, *_yq0} + Q1 := G1Affine{*_xq1, *_yq1} + + //TODO (perf): Add in E' first, then apply isogeny + g1Isogeny(&Q0) + g1Isogeny(&Q1) + + var _Q0, _Q1 bls12381.G1Jac + _Q0.FromAffine(toGurvyAffine(&Q0)) + _Q1.FromAffine(toGurvyAffine(&Q1)).AddAssign(&_Q0) + + _Q1.ClearCofactor(&_Q1) + + toGurvyAffine(&Q1).FromJacobian(&_Q1) + res := toGurvyAffine(&Q1) + return *res, nil +} diff --git a/vendor/github.com/IBM/mathlib/driver/kilic/bls12-381.go b/vendor/github.com/IBM/mathlib/driver/kilic/bls12-381.go new file mode 100644 index 00000000000..60f5ea36fcc --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/kilic/bls12-381.go @@ -0,0 +1,429 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kilic + +import ( + "fmt" + "math/big" + + "github.com/IBM/mathlib/driver" + "github.com/IBM/mathlib/driver/common" + bls12381 "github.com/kilic/bls12-381" +) + +/*********************************************************************/ + +type bls12_381G1 struct { + bls12381.PointG1 + bls12381.G1 +} + +func (g *bls12_381G1) Clone(a driver.G1) { + g.Set(&a.(*bls12_381G1).PointG1) +} + +func (e *bls12_381G1) Copy() driver.G1 { + c := &bls12_381G1{G1: *bls12381.NewG1()} + c.Set(&e.PointG1) + return c +} + +func (g *bls12_381G1) Add(a driver.G1) { + g.G1.Add(&g.PointG1, &g.PointG1, &a.(*bls12_381G1).PointG1) +} + +func (g *bls12_381G1) Mul(a driver.Zr) driver.G1 { + g1 := bls12381.NewG1() + res := g1.New() + + g1.MulScalarBig(res, &g.PointG1, &a.(*common.BaseZr).Int) + + return &bls12_381G1{ + G1: *g1, + PointG1: *res, + } +} + +func (g *bls12_381G1) Mul2(e driver.Zr, Q driver.G1, f driver.Zr) driver.G1 { + a := g.Mul(e) + b := Q.Mul(f) + a.Add(b) + + return a +} + +func (g *bls12_381G1) Equals(a driver.G1) bool { + g1 := bls12381.NewG1() + return g1.Equal(&a.(*bls12_381G1).PointG1, &g.PointG1) +} + +func (g *bls12_381G1) Bytes() []byte { + g1 := bls12381.NewG1() + raw := g1.ToUncompressed(&g.PointG1) + return raw[:] +} + +func (g *bls12_381G1) Compressed() []byte { + raw := g.G1.ToCompressed(&g.PointG1) + return raw[:] +} + +func (g *bls12_381G1) Sub(a driver.G1) { + g.G1.Sub(&g.PointG1, &g.PointG1, &a.(*bls12_381G1).PointG1) +} + +func (g *bls12_381G1) IsInfinity() bool { + return g.G1.IsZero(&g.PointG1) +} + +func (g *bls12_381G1) String() string { + gb := g.Bytes() + x := new(big.Int).SetBytes(gb[:len(gb)/2]) + y := new(big.Int).SetBytes(gb[len(gb)/2:]) + + return "(" + x.String() + "," + y.String() + ")" +} + +func (g *bls12_381G1) Neg() { + g.G1.Neg(&g.PointG1, &g.PointG1) +} + +/*********************************************************************/ + +type bls12_381G2 struct { + bls12381.PointG2 + bls12381.G2 +} + +func (g *bls12_381G2) Clone(a driver.G2) { + g.Set(&a.(*bls12_381G2).PointG2) +} + +func (e *bls12_381G2) Copy() driver.G2 { + c := &bls12_381G2{ + G2: *bls12381.NewG2(), + } + c.Set(&e.PointG2) + return c +} + +func (g *bls12_381G2) Mul(a driver.Zr) driver.G2 { + g2 := bls12381.NewG2() + res := g2.New() + + g2.MulScalarBig(res, &g.PointG2, &a.(*common.BaseZr).Int) + + return &bls12_381G2{ + G2: *g2, + PointG2: *res, + } +} + +func (g *bls12_381G2) Add(a driver.G2) { + g.G2.Add(&g.PointG2, &g.PointG2, &a.(*bls12_381G2).PointG2) +} + +func (g *bls12_381G2) Sub(a driver.G2) { + g.G2.Sub(&g.PointG2, &g.PointG2, &a.(*bls12_381G2).PointG2) +} + +func (g *bls12_381G2) Affine() { + g2 := bls12381.NewG2() + g.PointG2 = *g2.Affine(&g.PointG2) +} + +func (g *bls12_381G2) Bytes() []byte { + g2 := bls12381.NewG2() + raw := g2.ToUncompressed(&g.PointG2) + return raw[:] +} + +func (g *bls12_381G2) Compressed() []byte { + g2 := bls12381.NewG2() + raw := g2.ToCompressed(&g.PointG2) + return raw[:] +} + +func (g *bls12_381G2) String() string { + // FIXME + return "" +} + +func (g *bls12_381G2) Equals(a driver.G2) bool { + g2 := bls12381.NewG2() + return g2.Equal(&a.(*bls12_381G2).PointG2, &g.PointG2) +} + +/*********************************************************************/ + +type bls12_381Gt struct { + bls12381.E + bls12381.GT + GTInitialised bool +} + +func (g *bls12_381Gt) Exp(x driver.Zr) driver.Gt { + gt := bls12381.NewGT() + res := gt.New() + gt.Exp(res, &g.E, &x.(*common.BaseZr).Int) + + return &bls12_381Gt{ + E: *res, + GT: *gt, + GTInitialised: true, + } +} + +func (g *bls12_381Gt) Equals(a driver.Gt) bool { + return a.(*bls12_381Gt).E.Equal(&g.E) +} + +func (g *bls12_381Gt) Inverse() { + if !g.GTInitialised { + g.GT = *bls12381.NewGT() + } + g.GT.Inverse(&g.E, &g.E) +} + +func (g *bls12_381Gt) Mul(a driver.Gt) { + if !g.GTInitialised { + g.GT = *bls12381.NewGT() + } + g.GT.Mul(&g.E, &g.E, &a.(*bls12_381Gt).E) +} + +func (g *bls12_381Gt) IsUnity() bool { + return g.E.IsOne() +} + +func (g *bls12_381Gt) ToString() string { + // FIXME + return "" +} + +func (g *bls12_381Gt) Bytes() []byte { + if !g.GTInitialised { + g.GT = *bls12381.NewGT() + } + raw := g.GT.ToBytes(&g.E) + return raw[:] +} + +/*********************************************************************/ + +func NewBls12_381() *Bls12_381 { + return &Bls12_381{common.CurveBase{Modulus: *bls12381.NewG1().Q()}} +} + +func NewBls12_381BBS() *Bls12_381BBS { + return &Bls12_381BBS{*NewBls12_381()} +} + +type Bls12_381 struct { + common.CurveBase +} + +type Bls12_381BBS struct { + Bls12_381 +} + +func (c *Bls12_381) Pairing(p2 driver.G2, p1 driver.G1) driver.Gt { + bls := bls12381.NewEngine() + bls.AddPair(&p1.(*bls12_381G1).PointG1, &p2.(*bls12_381G2).PointG2) + + return &bls12_381Gt{ + E: *bls.Result(), + } +} + +func (c *Bls12_381) Pairing2(p2a, p2b driver.G2, p1a, p1b driver.G1) driver.Gt { + bls := bls12381.NewEngine() + bls.AddPair(&p1a.(*bls12_381G1).PointG1, &p2a.(*bls12_381G2).PointG2) + bls.AddPair(&p1b.(*bls12_381G1).PointG1, &p2b.(*bls12_381G2).PointG2) + + return &bls12_381Gt{ + E: *bls.Result(), + } +} + +func (c *Bls12_381) FExp(a driver.Gt) driver.Gt { + return a +} + +func (c *Bls12_381) GenG1() driver.G1 { + g := bls12381.NewG1() + g1 := g.One() + return &bls12_381G1{ + G1: *g, + PointG1: *g1, + } +} + +func (c *Bls12_381) GenG2() driver.G2 { + g := bls12381.NewG2() + g2 := g.One() + return &bls12_381G2{ + G2: *g, + PointG2: *g2, + } +} + +func (c *Bls12_381) GenGt() driver.Gt { + g1 := c.GenG1() + g2 := c.GenG2() + gengt := c.Pairing(g2, g1) + gengt = c.FExp(gengt) + return gengt +} + +func (c *Bls12_381) CoordinateByteSize() int { + return fpByteSize +} + +func (c *Bls12_381) G1ByteSize() int { + return 2 * fpByteSize +} + +func (c *Bls12_381) CompressedG1ByteSize() int { + return fpByteSize +} + +func (c *Bls12_381) G2ByteSize() int { + return 4 * fpByteSize +} + +func (c *Bls12_381) CompressedG2ByteSize() int { + return 2 * fpByteSize +} + +func (c *Bls12_381) ScalarByteSize() int { + return common.ScalarByteSize +} + +func (c *Bls12_381) NewG1() driver.G1 { + return &bls12_381G1{G1: *bls12381.NewG1()} +} + +func (c *Bls12_381) NewG2() driver.G2 { + return &bls12_381G2{G2: *bls12381.NewG2()} +} + +func (c *Bls12_381) NewG1FromBytes(b []byte) driver.G1 { + g1 := bls12381.NewG1() + p, err := g1.FromUncompressed(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return &bls12_381G1{ + PointG1: *p, + G1: *g1, + } +} + +func (c *Bls12_381) NewG2FromBytes(b []byte) driver.G2 { + g2 := bls12381.NewG2() + p, err := g2.FromUncompressed(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return &bls12_381G2{ + G2: *g2, + PointG2: *p, + } +} + +func (c *Bls12_381) NewG1FromCompressed(b []byte) driver.G1 { + g1 := bls12381.NewG1() + p, err := g1.FromCompressed(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return &bls12_381G1{ + PointG1: *p, + G1: *g1, + } +} + +func (c *Bls12_381) NewG2FromCompressed(b []byte) driver.G2 { + g2 := bls12381.NewG2() + p, err := g2.FromCompressed(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return &bls12_381G2{ + G2: *g2, + PointG2: *p, + } +} + +func (c *Bls12_381) NewGtFromBytes(b []byte) driver.Gt { + gt := bls12381.NewGT() + p, err := gt.FromBytes(b) + if err != nil { + panic(fmt.Sprintf("set bytes failed [%s]", err.Error())) + } + + return &bls12_381Gt{ + E: *p, + GT: *gt, + GTInitialised: true, + } +} + +func (c *Bls12_381) HashToG1(data []byte) driver.G1 { + g1 := bls12381.NewG1() + p, err := g1.HashToCurve(data, []byte{}) + if err != nil { + panic(fmt.Sprintf("HashToCurve failed [%s]", err.Error())) + } + + return &bls12_381G1{ + PointG1: *p, + G1: *g1, + } +} + +func (c *Bls12_381) HashToG1WithDomain(data, domain []byte) driver.G1 { + g1 := bls12381.NewG1() + p, err := g1.HashToCurve(data, domain) + if err != nil { + panic(fmt.Sprintf("HashToCurve failed [%s]", err.Error())) + } + + return &bls12_381G1{ + PointG1: *p, + G1: *g1, + } +} + +func (c *Bls12_381BBS) HashToG1(data []byte) driver.G1 { + p, err := HashToG1GenericBESwu(data, []byte{}) + if err != nil { + panic(fmt.Sprintf("HashToCurve failed [%s]", err.Error())) + } + + return &bls12_381G1{ + PointG1: *p, + G1: *bls12381.NewG1(), + } +} + +func (c *Bls12_381BBS) HashToG1WithDomain(data, domain []byte) driver.G1 { + p, err := HashToG1GenericBESwu(data, domain) + if err != nil { + panic(fmt.Sprintf("HashToCurve failed [%s]", err.Error())) + } + + return &bls12_381G1{ + PointG1: *p, + G1: *bls12381.NewG1(), + } +} diff --git a/vendor/github.com/IBM/mathlib/driver/kilic/custom.go b/vendor/github.com/IBM/mathlib/driver/kilic/custom.go new file mode 100644 index 00000000000..38a86a0431f --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/kilic/custom.go @@ -0,0 +1,343 @@ +/* +Copyright IBM Corp. All Rights Reserved. +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kilic + +import ( + "errors" + "hash" + "unsafe" + _ "unsafe" + + bls12381 "github.com/kilic/bls12-381" + "golang.org/x/crypto/blake2b" +) + +const fpByteSize = 48 + +const fpNumberOfLimbs = 6 + +type Fe [fpNumberOfLimbs]uint64 + +var modulus = Fe{0xb9feffffffffaaab, 0x1eabfffeb153ffff, 0x6730d2a0f6b0f624, 0x64774b84f38512bf, 0x4b1ba7b6434bacd7, 0x1a0111ea397fe69a} + +// r1 = r mod p +var r1 = &Fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493} + +var swuParamsForG1 = struct { + z *Fe + zInv *Fe + a *Fe + b *Fe + minusBOverA *Fe +}{ + a: &Fe{0x2f65aa0e9af5aa51, 0x86464c2d1e8416c3, 0xb85ce591b7bd31e2, 0x27e11c91b5f24e7c, 0x28376eda6bfc1835, 0x155455c3e5071d85}, + b: &Fe{0xfb996971fe22a1e0, 0x9aa93eb35b742d6f, 0x8c476013de99c5c4, 0x873e27c3a221e571, 0xca72b5e45a52d888, 0x06824061418a386b}, + z: &Fe{0x886c00000023ffdc, 0x0f70008d3090001d, 0x77672417ed5828c3, 0x9dac23e943dc1740, 0x50553f1b9c131521, 0x078c712fbe0ab6e8}, + zInv: &Fe{0x0e8a2e8ba2e83e10, 0x5b28ba2ca4d745d1, 0x678cd5473847377a, 0x4c506dd8a8076116, 0x9bcb227d79284139, 0x0e8d3154b0ba099a}, + minusBOverA: &Fe{0x052583c93555a7fe, 0x3b40d72430f93c82, 0x1b75faa0105ec983, 0x2527e7dc63851767, 0x99fffd1f34fc181d, 0x097cab54770ca0d3}, +} + +func (fe *Fe) setBytes(in []byte) *Fe { + l := len(in) + if l >= fpByteSize { + l = fpByteSize + } + padded := make([]byte, fpByteSize) + copy(padded[fpByteSize-l:], in[:]) + var a int + for i := 0; i < fpNumberOfLimbs; i++ { + a = fpByteSize - i*8 + fe[i] = uint64(padded[a-1]) | uint64(padded[a-2])<<8 | + uint64(padded[a-3])<<16 | uint64(padded[a-4])<<24 | + uint64(padded[a-5])<<32 | uint64(padded[a-6])<<40 | + uint64(padded[a-7])<<48 | uint64(padded[a-8])<<56 + } + return fe +} + +func (fe *Fe) isValid() bool { + return fe.cmp(&modulus) == -1 +} + +func (fe *Fe) cmp(fe2 *Fe) int { + for i := fpNumberOfLimbs - 1; i >= 0; i-- { + if fe[i] > fe2[i] { + return 1 + } else if fe[i] < fe2[i] { + return -1 + } + } + return 0 +} + +func (fe *Fe) isZero() bool { + return (fe[5] | fe[4] | fe[3] | fe[2] | fe[1] | fe[0]) == 0 +} + +func (fe *Fe) one() *Fe { + return fe.set(r1) +} + +func (fe *Fe) set(fe2 *Fe) *Fe { + fe[0] = fe2[0] + fe[1] = fe2[1] + fe[2] = fe2[2] + fe[3] = fe2[3] + fe[4] = fe2[4] + fe[5] = fe2[5] + return fe +} + +func (e *Fe) signBE() bool { + negZ, z := new(Fe), new(Fe) + fromMont(z, e) + neg(negZ, z) + return negZ.cmp(z) > -1 +} + +//go:linkname add github.com/kilic/bls12-381.add +func add(c, a, b *Fe) + +//go:linkname toMont github.com/kilic/bls12-381.toMont +func toMont(a, b *Fe) + +//go:linkname inverse github.com/kilic/bls12-381.inverse +func inverse(inv, e *Fe) + +//go:linkname isQuadraticNonResidue github.com/kilic/bls12-381.isQuadraticNonResidue +func isQuadraticNonResidue(a *Fe) bool + +//go:linkname sqrt github.com/kilic/bls12-381.sqrt +func sqrt(c, a *Fe) bool + +//go:linkname square github.com/kilic/bls12-381.square +func square(c, a *Fe) + +//go:linkname fromMont github.com/kilic/bls12-381.fromMont +func fromMont(c, a *Fe) + +//go:linkname neg github.com/kilic/bls12-381.neg +func neg(c, a *Fe) + +//go:linkname isogenyMapG1 github.com/kilic/bls12-381.isogenyMapG1 +func isogenyMapG1(x, y *Fe) + +func swuMapG1Pre(u *Fe) (*Fe, *Fe, *Fe) { + var params = swuParamsForG1 + var tv [4]*Fe + for i := 0; i < 4; i++ { + tv[i] = new(Fe) + } + square(tv[0], u) + mul(tv[0], tv[0], params.z) + square(tv[1], tv[0]) + x1 := new(Fe) + add(x1, tv[0], tv[1]) + inverse(x1, x1) + e1 := x1.isZero() + one := new(Fe).one() + add(x1, x1, one) + if e1 { + x1.set(params.zInv) + } + mul(x1, x1, params.minusBOverA) + gx1 := new(Fe) + square(gx1, x1) + add(gx1, gx1, params.a) + mul(gx1, gx1, x1) + add(gx1, gx1, params.b) + x2 := new(Fe) + mul(x2, tv[0], x1) + mul(tv[1], tv[0], tv[1]) + gx2 := new(Fe) + mul(gx2, gx1, tv[1]) + e2 := !isQuadraticNonResidue(gx1) + x, y2 := new(Fe), new(Fe) + if e2 { + x.set(x1) + y2.set(gx1) + } else { + x.set(x2) + y2.set(gx2) + } + y := new(Fe) + sqrt(y, y2) + + // This function is modified to perform the sign correction outside. + return x, y, u +} + +// SwuMapG1BE is implementation of Simplified Shallue-van de Woestijne-Ulas Method +// follows the implementation at draft-irtf-cfrg-hash-to-curve-06. +// uses big-endian variant: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-4.1.1 +func SwuMapG1BE(u *Fe) (*Fe, *Fe) { + x, y, u := swuMapG1Pre(u) + + if y.signBE() != u.signBE() { + neg(y, y) + } + return x, y +} + +type PointG1 [3]Fe + +func pointG1tobls12381PointG1(p *PointG1) *bls12381.PointG1 { + return (*bls12381.PointG1)(unsafe.Pointer(p)) +} + +func feAtPos(pos int, p *bls12381.PointG1) *Fe { + return (*Fe)(unsafe.Pointer(&(p[pos]))) +} + +func HashToG1GenericBESwu(data, domain []byte) (*bls12381.PointG1, error) { + hashFunc := func() hash.Hash { + // We pass a null key so error is impossible here. + h, _ := blake2b.New512(nil) //nolint:errcheck + return h + } + + p, err := HashToCurveGenericBESwu(data, domain, hashFunc) + if err != nil { + return nil, err + } + + return p, nil +} + +func HashToCurveGenericBESwu(msg, domain []byte, hashFunc func() hash.Hash) (*bls12381.PointG1, error) { + g := bls12381.NewG1() + hashRes, err := hashToFpXMD(hashFunc, msg, domain, 2) + if err != nil { + return nil, err + } + u0, u1 := hashRes[0], hashRes[1] + + x0, y0 := SwuMapG1BE(u0) + x1, y1 := SwuMapG1BE(u1) + one := new(Fe).one() + p0, p1 := pointG1tobls12381PointG1(&PointG1{*x0, *y0, *one}), pointG1tobls12381PointG1(&PointG1{*x1, *y1, *one}) + + g.Add(p0, p0, p1) + g.Affine(p0) + isogenyMapG1(feAtPos(0, p0), feAtPos(1, p0)) + g.ClearCofactor(p0) + return g.Affine(p0), nil +} + +func hashToFpXMD(f func() hash.Hash, msg []byte, domain []byte, count int) ([]*Fe, error) { + randBytes, err := expandMsgXMD(f, msg, domain, count*64) + if err != nil { + return nil, err + } + + els := make([]*Fe, count) + for i := 0; i < count; i++ { + var err error + + els[i], err = from64Bytes(randBytes[i*64 : (i+1)*64]) + if err != nil { + return nil, err + } + } + return els, nil +} + +func expandMsgXMD(f func() hash.Hash, msg []byte, domain []byte, outLen int) ([]byte, error) { + h := f() + domainLen := uint8(len(domain)) + if domainLen > 255 { + return nil, errors.New("invalid domain length") + } + + // DST_prime = DST || I2OSP(len(DST), 1) + // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) + _, _ = h.Write(make([]byte, h.BlockSize())) + _, _ = h.Write(msg) + _, _ = h.Write([]byte{uint8(outLen >> 8), uint8(outLen)}) + _, _ = h.Write([]byte{0}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + b0 := h.Sum(nil) + + // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) + h.Reset() + _, _ = h.Write(b0) + _, _ = h.Write([]byte{1}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + b1 := h.Sum(nil) + + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + ell := (outLen + h.Size() - 1) / h.Size() + bi := b1 + out := make([]byte, outLen) + for i := 1; i < ell; i++ { + h.Reset() + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + tmp := make([]byte, h.Size()) + for j := 0; j < h.Size(); j++ { + tmp[j] = b0[j] ^ bi[j] + } + _, _ = h.Write(tmp) + _, _ = h.Write([]byte{1 + uint8(i)}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + + // b_1 || ... || b_(ell - 1) + copy(out[(i-1)*h.Size():i*h.Size()], bi[:]) + bi = h.Sum(nil) + } + // b_ell + copy(out[(ell-1)*h.Size():], bi[:]) + + return out[:outLen], nil +} + +func from64Bytes(in []byte) (*Fe, error) { + if len(in) != 32*2 { + return nil, errors.New("input string must be equal 64 bytes") + } + a0 := make([]byte, fpByteSize) + copy(a0[fpByteSize-32:fpByteSize], in[:32]) + a1 := make([]byte, fpByteSize) + copy(a1[fpByteSize-32:fpByteSize], in[32:]) + e0, err := fromBytes(a0) + if err != nil { + return nil, err + } + e1, err := fromBytes(a1) + if err != nil { + return nil, err + } + // F = 2 ^ 256 * R + F := Fe{ + 0x75b3cd7c5ce820f, + 0x3ec6ba621c3edb0b, + 0x168a13d82bff6bce, + 0x87663c4bf8c449d2, + 0x15f34c83ddc8d830, + 0xf9628b49caa2e85, + } + + mul(e0, e0, &F) + add(e1, e1, e0) + return e1, nil +} + +func fromBytes(in []byte) (*Fe, error) { + fe := &Fe{} + if len(in) != fpByteSize { + return nil, errors.New("input string must be equal 48 bytes") + } + fe.setBytes(in) + if !fe.isValid() { + return nil, errors.New("must be less than modulus") + } + toMont(fe, fe) + return fe, nil +} diff --git a/vendor/github.com/IBM/mathlib/driver/kilic/custom_amd64.go b/vendor/github.com/IBM/mathlib/driver/kilic/custom_amd64.go new file mode 100644 index 00000000000..61498819963 --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/kilic/custom_amd64.go @@ -0,0 +1,30 @@ +//go:build amd64 && !generic + +/* +Copyright IBM Corp. All Rights Reserved. +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kilic + +import ( + _ "unsafe" + + "golang.org/x/sys/cpu" +) + +func init() { + if !cpu.X86.HasADX || !cpu.X86.HasBMI2 { + mul = mulNoADX + } +} + +var mul func(c, a, b *Fe) = mulADX + +//go:linkname mulADX github.com/kilic/bls12-381.mulADX +func mulADX(c, a, b *Fe) + +//go:linkname mulNoADX github.com/kilic/bls12-381.mulNoADX +func mulNoADX(c, a, b *Fe) diff --git a/vendor/github.com/IBM/mathlib/driver/kilic/custom_generic.go b/vendor/github.com/IBM/mathlib/driver/kilic/custom_generic.go new file mode 100644 index 00000000000..860a92e4812 --- /dev/null +++ b/vendor/github.com/IBM/mathlib/driver/kilic/custom_generic.go @@ -0,0 +1,171 @@ +//go:build !amd64 || generic + +/* +Copyright IBM Corp. All Rights Reserved. +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package kilic + +import "math/bits" + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} + +func mul(z, x, y *Fe) { + + var t [6]uint64 + var c [3]uint64 + { + // round 0 + v := x[0] + c[1], c[0] = bits.Mul64(v, y[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd1(v, y[1], c[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd1(v, y[2], c[1]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd1(v, y[3], c[1]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd1(v, y[4], c[1]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd1(v, y[5], c[1]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 1 + v := x[1] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 2 + v := x[2] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 3 + v := x[3] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 4 + v := x[4] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 5 + v := x[5] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], z[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], z[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], z[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], z[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + z[5], z[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) + z[1], b = bits.Sub64(z[1], 2210141511517208575, b) + z[2], b = bits.Sub64(z[2], 7435674573564081700, b) + z[3], b = bits.Sub64(z[3], 7239337960414712511, b) + z[4], b = bits.Sub64(z[4], 5412103778470702295, b) + z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) + } +} diff --git a/vendor/github.com/IBM/mathlib/driver/math.go b/vendor/github.com/IBM/mathlib/driver/math.go index b223fe47d59..ce394379e29 100644 --- a/vendor/github.com/IBM/mathlib/driver/math.go +++ b/vendor/github.com/IBM/mathlib/driver/math.go @@ -20,25 +20,34 @@ type Curve interface { GenG2() G2 GenGt() Gt GroupOrder() Zr - FieldBytes() int + CoordinateByteSize() int + G1ByteSize() int + CompressedG1ByteSize() int + G2ByteSize() int + CompressedG2ByteSize() int + ScalarByteSize() int NewG1() G1 NewG2() G2 - NewG1FromCoords(ix, iy Zr) G1 NewZrFromBytes(b []byte) Zr NewZrFromInt(i int64) Zr NewG1FromBytes(b []byte) G1 + NewG1FromCompressed(b []byte) G1 NewG2FromBytes(b []byte) G2 + NewG2FromCompressed(b []byte) G2 NewGtFromBytes(b []byte) Gt ModAdd(a, b, m Zr) Zr ModSub(a, b, m Zr) Zr HashToZr(data []byte) Zr HashToG1(data []byte) G1 + HashToG1WithDomain(data, domain []byte) G1 NewRandomZr(rng io.Reader) Zr Rand() (io.Reader, error) } type Zr interface { Plus(Zr) Zr + Minus(Zr) Zr + Mul(Zr) Zr Mod(Zr) PowMod(Zr) Zr InvModP(Zr) @@ -47,6 +56,7 @@ type Zr interface { Copy() Zr Clone(a Zr) String() string + Neg() } type G1 interface { @@ -57,9 +67,11 @@ type G1 interface { Mul2(e Zr, Q G1, f Zr) G1 Equals(G1) bool Bytes() []byte + Compressed() []byte Sub(G1) IsInfinity() bool String() string + Neg() } type G2 interface { @@ -70,6 +82,7 @@ type G2 interface { Sub(G2) Affine() Bytes() []byte + Compressed() []byte String() string Equals(G2) bool } @@ -81,4 +94,5 @@ type Gt interface { IsUnity() bool ToString() string Bytes() []byte + Exp(Zr) Gt } diff --git a/vendor/github.com/IBM/mathlib/math.go b/vendor/github.com/IBM/mathlib/math.go index 61e24b9499f..286be1b0bdf 100644 --- a/vendor/github.com/IBM/mathlib/math.go +++ b/vendor/github.com/IBM/mathlib/math.go @@ -15,6 +15,7 @@ import ( "github.com/IBM/mathlib/driver" "github.com/IBM/mathlib/driver/amcl" "github.com/IBM/mathlib/driver/gurvy" + "github.com/IBM/mathlib/driver/kilic" "github.com/pkg/errors" ) @@ -24,35 +25,148 @@ const ( FP256BN_AMCL CurveID = iota BN254 FP256BN_AMCL_MIRACL + BLS12_381 + BLS12_377_GURVY + BLS12_381_GURVY + BLS12_381_BBS + BLS12_381_BBS_GURVY ) +func CurveIDToString(id CurveID) string { + switch id { + case FP256BN_AMCL: + return "FP256BN_AMCL" + case BN254: + return "BN254" + case FP256BN_AMCL_MIRACL: + return "FP256BN_AMCL_MIRACL" + case BLS12_381: + return "BLS12_381" + case BLS12_377_GURVY: + return "BLS12_377_GURVY" + case BLS12_381_GURVY: + return "BLS12_381_GURVY" + case BLS12_381_BBS: + return "BLS12_381_BBS" + case BLS12_381_BBS_GURVY: + return "BLS12_381_BBS_GURVY" + default: + panic(fmt.Sprintf("unknown curve %d", id)) + } +} + var Curves []*Curve = []*Curve{ { - c: &amcl.Fp256bn{}, - GenG1: &G1{g1: (&amcl.Fp256bn{}).GenG1(), curveID: FP256BN_AMCL}, - GenG2: &G2{g2: (&amcl.Fp256bn{}).GenG2(), curveID: FP256BN_AMCL}, - GenGt: &Gt{gt: (&amcl.Fp256bn{}).GenGt(), curveID: FP256BN_AMCL}, - GroupOrder: &Zr{zr: (&amcl.Fp256bn{}).GroupOrder(), curveID: FP256BN_AMCL}, - FieldBytes: (&amcl.Fp256bn{}).FieldBytes(), - curveID: FP256BN_AMCL, + c: amcl.NewFp256bn(), + GenG1: &G1{g1: (&amcl.Fp256bn{}).GenG1(), curveID: FP256BN_AMCL}, + GenG2: &G2{g2: (&amcl.Fp256bn{}).GenG2(), curveID: FP256BN_AMCL}, + GenGt: &Gt{gt: (&amcl.Fp256bn{}).GenGt(), curveID: FP256BN_AMCL}, + GroupOrder: &Zr{zr: amcl.NewFp256bn().GroupOrder(), curveID: FP256BN_AMCL}, + CoordByteSize: (&amcl.Fp256bn{}).CoordinateByteSize(), + G1ByteSize: (&amcl.Fp256bn{}).G1ByteSize(), + CompressedG1ByteSize: (&amcl.Fp256bn{}).CompressedG1ByteSize(), + G2ByteSize: (&amcl.Fp256bn{}).G2ByteSize(), + CompressedG2ByteSize: (&amcl.Fp256bn{}).CompressedG2ByteSize(), + ScalarByteSize: (&amcl.Fp256bn{}).ScalarByteSize(), + curveID: FP256BN_AMCL, + }, + { + c: gurvy.NewBn254(), + GenG1: &G1{g1: (&gurvy.Bn254{}).GenG1(), curveID: BN254}, + GenG2: &G2{g2: (&gurvy.Bn254{}).GenG2(), curveID: BN254}, + GenGt: &Gt{gt: (&gurvy.Bn254{}).GenGt(), curveID: BN254}, + GroupOrder: &Zr{zr: gurvy.NewBn254().GroupOrder(), curveID: BN254}, + CoordByteSize: (&gurvy.Bn254{}).CoordinateByteSize(), + G1ByteSize: (&gurvy.Bn254{}).G1ByteSize(), + CompressedG1ByteSize: (&gurvy.Bn254{}).CompressedG1ByteSize(), + G2ByteSize: (&gurvy.Bn254{}).G2ByteSize(), + CompressedG2ByteSize: (&gurvy.Bn254{}).CompressedG2ByteSize(), + ScalarByteSize: (&gurvy.Bn254{}).ScalarByteSize(), + curveID: BN254, + }, + { + c: amcl.NewFp256Miraclbn(), + GenG1: &G1{g1: (&amcl.Fp256Miraclbn{}).GenG1(), curveID: FP256BN_AMCL_MIRACL}, + GenG2: &G2{g2: (&amcl.Fp256Miraclbn{}).GenG2(), curveID: FP256BN_AMCL_MIRACL}, + GenGt: &Gt{gt: (&amcl.Fp256Miraclbn{}).GenGt(), curveID: FP256BN_AMCL_MIRACL}, + GroupOrder: &Zr{zr: amcl.NewFp256Miraclbn().GroupOrder(), curveID: FP256BN_AMCL_MIRACL}, + CoordByteSize: (&amcl.Fp256Miraclbn{}).CoordinateByteSize(), + G1ByteSize: (&amcl.Fp256Miraclbn{}).G1ByteSize(), + CompressedG1ByteSize: (&amcl.Fp256Miraclbn{}).CompressedG1ByteSize(), + G2ByteSize: (&amcl.Fp256Miraclbn{}).G2ByteSize(), + CompressedG2ByteSize: (&amcl.Fp256Miraclbn{}).CompressedG2ByteSize(), + ScalarByteSize: (&amcl.Fp256Miraclbn{}).ScalarByteSize(), + curveID: FP256BN_AMCL_MIRACL, + }, + { + c: kilic.NewBls12_381(), + GenG1: &G1{g1: (&kilic.Bls12_381{}).GenG1(), curveID: BLS12_381}, + GenG2: &G2{g2: (&kilic.Bls12_381{}).GenG2(), curveID: BLS12_381}, + GenGt: &Gt{gt: (&kilic.Bls12_381{}).GenGt(), curveID: BLS12_381}, + GroupOrder: &Zr{zr: kilic.NewBls12_381().GroupOrder(), curveID: BLS12_381}, + CoordByteSize: (&kilic.Bls12_381{}).CoordinateByteSize(), + G1ByteSize: (&kilic.Bls12_381{}).G1ByteSize(), + CompressedG1ByteSize: (&kilic.Bls12_381{}).CompressedG1ByteSize(), + G2ByteSize: (&kilic.Bls12_381{}).G2ByteSize(), + CompressedG2ByteSize: (&kilic.Bls12_381{}).CompressedG2ByteSize(), + ScalarByteSize: (&kilic.Bls12_381{}).ScalarByteSize(), + curveID: BLS12_381, + }, + { + c: gurvy.NewBls12_377(), + GenG1: &G1{g1: (&gurvy.Bls12_377{}).GenG1(), curveID: BLS12_377_GURVY}, + GenG2: &G2{g2: (&gurvy.Bls12_377{}).GenG2(), curveID: BLS12_377_GURVY}, + GenGt: &Gt{gt: (&gurvy.Bls12_377{}).GenGt(), curveID: BLS12_377_GURVY}, + GroupOrder: &Zr{zr: gurvy.NewBls12_377().GroupOrder(), curveID: BLS12_377_GURVY}, + CoordByteSize: (&gurvy.Bls12_377{}).CoordinateByteSize(), + G1ByteSize: (&gurvy.Bls12_377{}).G1ByteSize(), + CompressedG1ByteSize: (&gurvy.Bls12_377{}).CompressedG1ByteSize(), + G2ByteSize: (&gurvy.Bls12_377{}).G2ByteSize(), + CompressedG2ByteSize: (&gurvy.Bls12_377{}).CompressedG2ByteSize(), + ScalarByteSize: (&gurvy.Bls12_377{}).ScalarByteSize(), + curveID: BLS12_377_GURVY, + }, + { + c: gurvy.NewBls12_381(), + GenG1: &G1{g1: (&gurvy.Bls12_381{}).GenG1(), curveID: BLS12_381_GURVY}, + GenG2: &G2{g2: (&gurvy.Bls12_381{}).GenG2(), curveID: BLS12_381_GURVY}, + GenGt: &Gt{gt: (&gurvy.Bls12_381{}).GenGt(), curveID: BLS12_381_GURVY}, + GroupOrder: &Zr{zr: gurvy.NewBls12_381().GroupOrder(), curveID: BLS12_381_GURVY}, + CoordByteSize: (&gurvy.Bls12_381{}).CoordinateByteSize(), + G1ByteSize: (&gurvy.Bls12_381{}).G1ByteSize(), + CompressedG1ByteSize: (&gurvy.Bls12_381{}).CompressedG1ByteSize(), + G2ByteSize: (&gurvy.Bls12_381{}).G2ByteSize(), + CompressedG2ByteSize: (&gurvy.Bls12_381{}).CompressedG2ByteSize(), + ScalarByteSize: (&gurvy.Bls12_381{}).ScalarByteSize(), + curveID: BLS12_381_GURVY, }, { - c: &gurvy.Bn254{}, - GenG1: &G1{g1: (&gurvy.Bn254{}).GenG1(), curveID: BN254}, - GenG2: &G2{g2: (&gurvy.Bn254{}).GenG2(), curveID: BN254}, - GenGt: &Gt{gt: (&gurvy.Bn254{}).GenGt(), curveID: BN254}, - GroupOrder: &Zr{zr: (&gurvy.Bn254{}).GroupOrder(), curveID: BN254}, - FieldBytes: (&gurvy.Bn254{}).FieldBytes(), - curveID: BN254, + c: kilic.NewBls12_381BBS(), + GenG1: &G1{g1: kilic.NewBls12_381BBS().GenG1(), curveID: BLS12_381_BBS}, + GenG2: &G2{g2: kilic.NewBls12_381BBS().GenG2(), curveID: BLS12_381_BBS}, + GenGt: &Gt{gt: kilic.NewBls12_381BBS().GenGt(), curveID: BLS12_381_BBS}, + GroupOrder: &Zr{zr: kilic.NewBls12_381().GroupOrder(), curveID: BLS12_381_BBS}, + CoordByteSize: kilic.NewBls12_381BBS().CoordinateByteSize(), + G1ByteSize: kilic.NewBls12_381BBS().G1ByteSize(), + CompressedG1ByteSize: kilic.NewBls12_381BBS().CompressedG1ByteSize(), + G2ByteSize: kilic.NewBls12_381BBS().G2ByteSize(), + CompressedG2ByteSize: kilic.NewBls12_381BBS().CompressedG2ByteSize(), + ScalarByteSize: kilic.NewBls12_381BBS().ScalarByteSize(), + curveID: BLS12_381_BBS, }, { - c: &amcl.Fp256Miraclbn{}, - GenG1: &G1{g1: (&amcl.Fp256Miraclbn{}).GenG1(), curveID: FP256BN_AMCL_MIRACL}, - GenG2: &G2{g2: (&amcl.Fp256Miraclbn{}).GenG2(), curveID: FP256BN_AMCL_MIRACL}, - GenGt: &Gt{gt: (&amcl.Fp256Miraclbn{}).GenGt(), curveID: FP256BN_AMCL_MIRACL}, - GroupOrder: &Zr{zr: (&amcl.Fp256Miraclbn{}).GroupOrder(), curveID: FP256BN_AMCL_MIRACL}, - FieldBytes: (&amcl.Fp256Miraclbn{}).FieldBytes(), - curveID: FP256BN_AMCL_MIRACL, + c: gurvy.NewBls12_381BBS(), + GenG1: &G1{g1: gurvy.NewBls12_381BBS().GenG1(), curveID: BLS12_381_BBS_GURVY}, + GenG2: &G2{g2: gurvy.NewBls12_381BBS().GenG2(), curveID: BLS12_381_BBS_GURVY}, + GenGt: &Gt{gt: gurvy.NewBls12_381BBS().GenGt(), curveID: BLS12_381_BBS_GURVY}, + GroupOrder: &Zr{zr: gurvy.NewBls12_381().GroupOrder(), curveID: BLS12_381_BBS_GURVY}, + CoordByteSize: gurvy.NewBls12_381BBS().CoordinateByteSize(), + G1ByteSize: gurvy.NewBls12_381BBS().G1ByteSize(), + CompressedG1ByteSize: gurvy.NewBls12_381BBS().CompressedG1ByteSize(), + G2ByteSize: gurvy.NewBls12_381BBS().G2ByteSize(), + CompressedG2ByteSize: gurvy.NewBls12_381BBS().CompressedG2ByteSize(), + ScalarByteSize: gurvy.NewBls12_381BBS().ScalarByteSize(), + curveID: BLS12_381_BBS_GURVY, }, } @@ -67,6 +181,14 @@ func (z *Zr) Plus(a *Zr) *Zr { return &Zr{zr: z.zr.Plus(a.zr), curveID: z.curveID} } +func (z *Zr) Minus(a *Zr) *Zr { + return &Zr{zr: z.zr.Minus(a.zr), curveID: z.curveID} +} + +func (z *Zr) Mul(a *Zr) *Zr { + return &Zr{zr: z.zr.Mul(a.zr), curveID: z.curveID} +} + func (z *Zr) Mod(a *Zr) { z.zr.Mod(a.zr) } @@ -99,6 +221,10 @@ func (z *Zr) String() string { return z.zr.String() } +func (z *Zr) Neg() { + z.zr.Neg() +} + var zerobytes = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} var onebytes = []byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} @@ -146,6 +272,10 @@ func (g *G1) Bytes() []byte { return g.g1.Bytes() } +func (g *G1) Compressed() []byte { + return g.g1.Compressed() +} + func (g *G1) Sub(a *G1) { g.g1.Sub(a.g1) } @@ -158,6 +288,10 @@ func (g *G1) String() string { return g.g1.String() } +func (g *G1) Neg() { + g.g1.Neg() +} + /*********************************************************************/ type G2 struct { @@ -193,6 +327,10 @@ func (g *G2) Bytes() []byte { return g.g2.Bytes() } +func (g *G2) Compressed() []byte { + return g.g2.Compressed() +} + func (g *G2) String() string { return g.g2.String() } @@ -220,6 +358,10 @@ func (g *Gt) Mul(a *Gt) { g.gt.Mul(a.gt) } +func (g *Gt) Exp(z *Zr) *Gt { + return &Gt{gt: g.gt.Exp(z.zr), curveID: g.curveID} +} + func (g *Gt) IsUnity() bool { return g.gt.IsUnity() } @@ -235,13 +377,18 @@ func (g *Gt) Bytes() []byte { /*********************************************************************/ type Curve struct { - c driver.Curve - GenG1 *G1 - GenG2 *G2 - GenGt *Gt - GroupOrder *Zr - FieldBytes int - curveID CurveID + c driver.Curve + GenG1 *G1 + GenG2 *G2 + GenGt *Gt + GroupOrder *Zr + CoordByteSize int + G1ByteSize int + CompressedG1ByteSize int + G2ByteSize int + CompressedG2ByteSize int + ScalarByteSize int + curveID CurveID } func (c *Curve) Rand() (io.Reader, error) { @@ -280,6 +427,30 @@ func (c *Curve) NewG2FromBytes(b []byte) (p *G2, err error) { return } +func (c *Curve) NewG1FromCompressed(b []byte) (p *G1, err error) { + defer func() { + if r := recover(); r != nil { + err = errors.Errorf("failure [%s]", r) + p = nil + } + }() + + p = &G1{g1: c.c.NewG1FromCompressed(b), curveID: c.curveID} + return +} + +func (c *Curve) NewG2FromCompressed(b []byte) (p *G2, err error) { + defer func() { + if r := recover(); r != nil { + err = errors.Errorf("failure [%s]", r) + p = nil + } + }() + + p = &G2{g2: c.c.NewG2FromCompressed(b), curveID: c.curveID} + return +} + func (c *Curve) NewGtFromBytes(b []byte) (p *Gt, err error) { defer func() { if r := recover(); r != nil { @@ -296,10 +467,6 @@ func (c *Curve) NewZrFromInt(i int64) *Zr { return &Zr{zr: c.c.NewZrFromInt(i), curveID: c.curveID} } -// func (c *Curve) NewG1FromCoords(ix, iy *Zr) *G1 { -// return &G1{c.c.NewG1FromCoords(ix.zr, iy.zr)} -// } - func (c *Curve) NewG2() *G2 { return &G2{g2: c.c.NewG2(), curveID: c.curveID} } @@ -328,6 +495,10 @@ func (c *Curve) HashToG1(data []byte) *G1 { return &G1{g1: c.c.HashToG1(data), curveID: c.curveID} } +func (c *Curve) HashToG1WithDomain(data, domain []byte) *G1 { + return &G1{g1: c.c.HashToG1WithDomain(data, domain), curveID: c.curveID} +} + func (c *Curve) ModSub(a, b, m *Zr) *Zr { return &Zr{zr: c.c.ModSub(a.zr, b.zr, m.zr), curveID: c.curveID} } @@ -343,5 +514,3 @@ func (c *Curve) ModMul(a1, b1, m *Zr) *Zr { func (c *Curve) ModNeg(a1, m *Zr) *Zr { return &Zr{zr: c.c.ModNeg(a1.zr, m.zr), curveID: c.curveID} } - -/*********************************************************************/ diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/LICENSE b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/LICENSE new file mode 100644 index 00000000000..8f71f43fee3 --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/bbs12381g2pub.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/bbs12381g2pub.go new file mode 100644 index 00000000000..6b4353295be --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/bbs12381g2pub.go @@ -0,0 +1,338 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +// Package bbs12381g2pub contains BBS+ signing primitives and keys. Although it can be used directly, it is recommended +// to use BBS+ keys created by the kms along with the framework's Crypto service. +// +// The default local Crypto service is found at: +// "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/tinkcrypto" +// +// While the remote Crypto service is found at: +// "github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/webkms" +package bbs12381g2pub + +import ( + "errors" + "fmt" + "sort" + + ml "github.com/IBM/mathlib" +) + +// nolint:gochecknoglobals +var curve = ml.Curves[ml.BLS12_381_BBS] + +// BBSG2Pub defines BBS+ signature scheme where public key is a point in the field of G2. +// BBS+ signature scheme (as defined in https://eprint.iacr.org/2016/663.pdf, section 4.3). +type BBSG2Pub struct{} + +// New creates a new BBSG2Pub. +func New() *BBSG2Pub { + return &BBSG2Pub{} +} + +// Number of bytes in scalar compressed form. +const frCompressedSize = 32 + +var ( + // nolint:gochecknoglobals + // Signature length. + bls12381SignatureLen = curve.CompressedG1ByteSize + 2*frCompressedSize + + // nolint:gochecknoglobals + // Default BLS 12-381 public key length in G2 field. + bls12381G2PublicKeyLen = curve.CompressedG2ByteSize + + // nolint:gochecknoglobals + // Number of bytes in G1 X coordinate. + g1CompressedSize = curve.CompressedG1ByteSize + + // nolint:gochecknoglobals + // Number of bytes in G1 X and Y coordinates. + g1UncompressedSize = curve.G1ByteSize + + // nolint:gochecknoglobals + // Number of bytes in G2 X(a, b) and Y(a, b) coordinates. + g2UncompressedSize = curve.G2ByteSize + + // nolint:gochecknoglobals + // Number of bytes in scalar uncompressed form. + frUncompressedSize = curve.ScalarByteSize +) + +// Verify makes BLS BBS12-381 signature verification. +func (bbs *BBSG2Pub) Verify(messages [][]byte, sigBytes, pubKeyBytes []byte) error { + signature, err := ParseSignature(sigBytes) + if err != nil { + return fmt.Errorf("parse signature: %w", err) + } + + pubKey, err := UnmarshalPublicKey(pubKeyBytes) + if err != nil { + return fmt.Errorf("parse public key: %w", err) + } + + messagesCount := len(messages) + + publicKeyWithGenerators, err := pubKey.ToPublicKeyWithGenerators(messagesCount) + if err != nil { + return fmt.Errorf("build generators from public key: %w", err) + } + + messagesFr := messagesToFr(messages) + + return signature.Verify(messagesFr, publicKeyWithGenerators) +} + +// Sign signs the one or more messages using private key in compressed form. +func (bbs *BBSG2Pub) Sign(messages [][]byte, privKeyBytes []byte) ([]byte, error) { + privKey, err := UnmarshalPrivateKey(privKeyBytes) + if err != nil { + return nil, fmt.Errorf("unmarshal private key: %w", err) + } + + if len(messages) == 0 { + return nil, errors.New("messages are not defined") + } + + return bbs.SignWithKey(messages, nil, privKey) +} + +// VerifyProof verifies BBS+ signature proof for one ore more revealed messages. +func (bbs *BBSG2Pub) VerifyProof(messagesBytes [][]byte, proof, nonce, pubKeyBytes []byte) error { + + messages := messagesToFr(messagesBytes) + + return bbs.VerifyProofFr(messages, proof, nonce, pubKeyBytes) +} + +// VerifyProof verifies BBS+ signature proof for one ore more revealed messages. +func (bbs *BBSG2Pub) VerifyProofFr(messages []*SignatureMessage, proof, nonce, pubKeyBytes []byte) error { + payload, err := ParsePoKPayload(proof) + if err != nil { + return fmt.Errorf("parse signature proof: %w", err) + } + + signatureProof, err := ParseSignatureProof(proof[payload.LenInBytes():]) + if err != nil { + return fmt.Errorf("parse signature proof: %w", err) + } + + pubKey, err := UnmarshalPublicKey(pubKeyBytes) + if err != nil { + return fmt.Errorf("parse public key: %w", err) + } + + publicKeyWithGenerators, err := pubKey.ToPublicKeyWithGenerators(payload.messagesCount) + if err != nil { + return fmt.Errorf("build generators from public key: %w", err) + } + + if len(payload.Revealed) > len(messages) { + return fmt.Errorf("payload revealed bigger from messages") + } + + revealedMessages := make(map[int]*SignatureMessage) + for i := range payload.Revealed { + revealedMessages[payload.Revealed[i]] = messages[i] + } + + challengeBytes := signatureProof.GetBytesForChallenge(revealedMessages, publicKeyWithGenerators) + proofNonce := ParseProofNonce(nonce) + proofNonceBytes := proofNonce.ToBytes() + challengeBytes = append(challengeBytes, proofNonceBytes...) + proofChallenge := FrFromOKM(challengeBytes) + + return signatureProof.Verify(proofChallenge, publicKeyWithGenerators, revealedMessages, messages) +} + +// DeriveProof derives a proof of BBS+ signature with some messages disclosed. +func (bbs *BBSG2Pub) DeriveProof(messages [][]byte, sigBytes, nonce, pubKeyBytes []byte, + revealedIndexes []int) ([]byte, error) { + + return bbs.DeriveProofZr(messagesToFr(messages), sigBytes, nonce, pubKeyBytes, revealedIndexes) +} + +// DeriveProof derives a proof of BBS+ signature with some messages disclosed. +func (bbs *BBSG2Pub) DeriveProofZr(messagesFr []*SignatureMessage, sigBytes, nonce, pubKeyBytes []byte, + revealedIndexes []int) ([]byte, error) { + + if len(revealedIndexes) == 0 { + return nil, errors.New("no message to reveal") + } + + sort.Ints(revealedIndexes) + + messagesCount := len(messagesFr) + + pubKey, err := UnmarshalPublicKey(pubKeyBytes) + if err != nil { + return nil, fmt.Errorf("parse public key: %w", err) + } + + publicKeyWithGenerators, err := pubKey.ToPublicKeyWithGenerators(messagesCount) + if err != nil { + return nil, fmt.Errorf("build generators from public key: %w", err) + } + + signature, err := ParseSignature(sigBytes) + if err != nil { + return nil, fmt.Errorf("parse signature: %w", err) + } + + pokSignature, err := NewPoKOfSignature(signature, messagesFr, revealedIndexes, publicKeyWithGenerators) + if err != nil { + return nil, fmt.Errorf("init proof of knowledge signature: %w", err) + } + + challengeBytes := pokSignature.ToBytes() + + proofNonce := ParseProofNonce(nonce) + proofNonceBytes := proofNonce.ToBytes() + challengeBytes = append(challengeBytes, proofNonceBytes...) + + proofChallenge := FrFromOKM(challengeBytes) + + proof := pokSignature.GenerateProof(proofChallenge) + + payload := NewPoKPayload(messagesCount, revealedIndexes) + + payloadBytes, err := payload.ToBytes() + if err != nil { + return nil, fmt.Errorf("derive proof: paylod to bytes: %w", err) + } + + signatureProofBytes := append(payloadBytes, proof.ToBytes()...) + + return signatureProofBytes, nil +} + +// SignWithKey signs the one or more messages using BBS+ key pair. +func (bbs *BBSG2Pub) SignWithKey(messages [][]byte, commitment *ml.G1, privKey *PrivateKey) ([]byte, error) { + + messagesFr := make([]*SignatureMessage, 0, len(messages)) + + for i, msg := range messages { + if len(msg) == 0 { + continue + } + + messagesFr = append(messagesFr, ParseSignatureMessage(messages[i], i)) + } + + return bbs.SignWithKeyFr(messagesFr, len(messages), commitment, privKey) +} + +// SignWithKey signs the one or more messages using BBS+ key pair. +func (bbs *BBSG2Pub) SignWithKeyFr(messagesFr []*SignatureMessage, messagesCount int, commitment *ml.G1, privKey *PrivateKey) ([]byte, error) { + var err error + + pubKey := privKey.PublicKey() + + pubKeyWithGenerators, err := pubKey.ToPublicKeyWithGenerators(messagesCount) + if err != nil { + return nil, fmt.Errorf("build generators from public key: %w", err) + } + + e, s := createRandSignatureFr(), createRandSignatureFr() + exp := privKey.FR.Copy() + exp = exp.Plus(e) + exp.InvModP(curve.GroupOrder) + + b := computeB(s, messagesFr, pubKeyWithGenerators) + if len(messagesFr) != messagesCount { + b.Add(commitment) + } + + sig := b.Mul(frToRepr(exp)) + + signature := &Signature{ + A: sig, + E: e, + S: s, + } + + return signature.ToBytes() +} + +func computeB(s *ml.Zr, messages []*SignatureMessage, key *PublicKeyWithGenerators) *ml.G1 { + const basesOffset = 2 + + cb := NewCommitmentBuilder(len(messages) + basesOffset) + + cb.Add(curve.GenG1, curve.NewZrFromInt(1)) + cb.Add(key.H0, s) + + for i := 0; i < len(messages); i++ { + cb.Add(key.H[messages[i].Idx], messages[i].FR) + } + + return cb.Build() +} + +type commitmentBuilder struct { + bases []*ml.G1 + scalars []*ml.Zr +} + +func NewCommitmentBuilder(expectedSize int) *commitmentBuilder { + return &commitmentBuilder{ + bases: make([]*ml.G1, 0, expectedSize), + scalars: make([]*ml.Zr, 0, expectedSize), + } +} + +func (cb *commitmentBuilder) Add(base *ml.G1, scalar *ml.Zr) { + cb.bases = append(cb.bases, base) + cb.scalars = append(cb.scalars, scalar) +} + +func (cb *commitmentBuilder) Build() *ml.G1 { + return sumOfG1Products(cb.bases, cb.scalars) +} + +func sumOfG1Products(bases []*ml.G1, scalars []*ml.Zr) *ml.G1 { + var res *ml.G1 + + for i := 0; i < len(bases); i++ { + b := bases[i] + s := scalars[i] + + g := b.Mul(frToRepr(s)) + if res == nil { + res = g + } else { + res.Add(g) + } + } + + return res +} + +func compareTwoPairings(p1 *ml.G1, q1 *ml.G2, + p2 *ml.G1, q2 *ml.G2) bool { + p := curve.Pairing2(q1, p1, q2, p2) + p = curve.FExp(p) + + return p.IsUnity() +} + +// ProofNonce is a nonce for Proof of Knowledge proof. +type ProofNonce struct { + fr *ml.Zr +} + +// ParseProofNonce creates a new ProofNonce from bytes. +func ParseProofNonce(proofNonceBytes []byte) *ProofNonce { + return &ProofNonce{ + FrFromOKM(proofNonceBytes), + } +} + +// ToBytes converts ProofNonce into bytes. +func (pn *ProofNonce) ToBytes() []byte { + return frToRepr(pn.fr).Bytes() +} diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/fr.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/fr.go new file mode 100644 index 00000000000..c43a2a36672 --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/fr.go @@ -0,0 +1,71 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package bbs12381g2pub + +import ( + "crypto/rand" + + ml "github.com/IBM/mathlib" + "golang.org/x/crypto/blake2b" +) + +func parseFr(data []byte) *ml.Zr { + return curve.NewZrFromBytes(data) +} + +// nolint:gochecknoglobals +var f2192Bytes = []byte{ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +} + +func f2192() *ml.Zr { + return curve.NewZrFromBytes(f2192Bytes) +} + +func FrFromOKM(message []byte) *ml.Zr { + const ( + eightBytes = 8 + okmMiddle = 24 + ) + + // We pass a null key so error is impossible here. + h, _ := blake2b.New384(nil) //nolint:errcheck + + // blake2b.digest() does not return an error. + _, _ = h.Write(message) + okm := h.Sum(nil) + emptyEightBytes := make([]byte, eightBytes) + + elm := curve.NewZrFromBytes(append(emptyEightBytes, okm[:okmMiddle]...)) + elm = elm.Mul(f2192()) + + fr := curve.NewZrFromBytes(append(emptyEightBytes, okm[okmMiddle:]...)) + elm = elm.Plus(fr) + + return elm +} + +func frToRepr(fr *ml.Zr) *ml.Zr { + return fr.Copy() +} + +func messagesToFr(messages [][]byte) []*SignatureMessage { + messagesFr := make([]*SignatureMessage, len(messages)) + + for i := range messages { + messagesFr[i] = ParseSignatureMessage(messages[i], i) + } + + return messagesFr +} + +func createRandSignatureFr() *ml.Zr { + return curve.NewRandomZr(rand.Reader) +} diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/keys.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/keys.go new file mode 100644 index 00000000000..dd6da5bd6d5 --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/keys.go @@ -0,0 +1,196 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package bbs12381g2pub + +import ( + "crypto/rand" + "errors" + "fmt" + "hash" + "io" + + ml "github.com/IBM/mathlib" + "golang.org/x/crypto/hkdf" +) + +var ( + // nolint:gochecknoglobals + seedSize = frCompressedSize + + // nolint:gochecknoglobals + generateKeySalt = "BBS-SIG-KEYGEN-SALT-" +) + +// PublicKey defines BLS Public Key. +type PublicKey struct { + PointG2 *ml.G2 +} + +// PrivateKey defines BLS Public Key. +type PrivateKey struct { + FR *ml.Zr +} + +// PublicKeyWithGenerators extends PublicKey with a blinding generator h0, a commitment to the secret key w, +// and a generator for each message h. +type PublicKeyWithGenerators struct { + H0 *ml.G1 + H []*ml.G1 + + w *ml.G2 + + messagesCount int +} + +// ToPublicKeyWithGenerators creates PublicKeyWithGenerators from the PublicKey. +func (pk *PublicKey) ToPublicKeyWithGenerators(messagesCount int) (*PublicKeyWithGenerators, error) { + offset := g2UncompressedSize + 1 + + data := calcData(pk, messagesCount) + + h0 := hashToG1(data) + + h := make([]*ml.G1, messagesCount) + + for i := 1; i <= messagesCount; i++ { + dataCopy := make([]byte, len(data)) + copy(dataCopy, data) + + iBytes := uint32ToBytes(uint32(i)) + + for j := 0; j < len(iBytes); j++ { + dataCopy[j+offset] = iBytes[j] + } + + h[i-1] = hashToG1(dataCopy) + } + + return &PublicKeyWithGenerators{ + H0: h0, + H: h, + w: pk.PointG2, + messagesCount: messagesCount, + }, nil +} + +func calcData(key *PublicKey, messagesCount int) []byte { + data := key.PointG2.Bytes() + + data = append(data, 0, 0, 0, 0, 0, 0) + + mcBytes := uint32ToBytes(uint32(messagesCount)) + + data = append(data, mcBytes...) + + return data +} + +func hashToG1(data []byte) *ml.G1 { + var dstG1 = []byte("BLS12381G1_XMD:BLAKE2B_SSWU_RO_BBS+_SIGNATURES:1_0_0") + + return curve.HashToG1WithDomain(data, dstG1) +} + +// UnmarshalPrivateKey unmarshals PrivateKey. +func UnmarshalPrivateKey(privKeyBytes []byte) (*PrivateKey, error) { + if len(privKeyBytes) != frCompressedSize { + return nil, errors.New("invalid size of private key") + } + + fr := parseFr(privKeyBytes) + + return &PrivateKey{ + FR: fr, + }, nil +} + +// Marshal marshals PrivateKey. +func (k *PrivateKey) Marshal() ([]byte, error) { + bytes := k.FR.Bytes() + return bytes, nil +} + +// PublicKey returns a Public Key as G2 point generated from the Private Key. +func (k *PrivateKey) PublicKey() *PublicKey { + pointG2 := curve.GenG2.Mul(frToRepr(k.FR)) + + return &PublicKey{pointG2} +} + +// UnmarshalPublicKey parses a PublicKey from bytes. +func UnmarshalPublicKey(pubKeyBytes []byte) (*PublicKey, error) { + if len(pubKeyBytes) != bls12381G2PublicKeyLen { + return nil, errors.New("invalid size of public key") + } + + pointG2, err := curve.NewG2FromCompressed(pubKeyBytes) + if err != nil { + return nil, fmt.Errorf("deserialize public key: %w", err) + } + + return &PublicKey{ + PointG2: pointG2, + }, nil +} + +// Marshal marshals PublicKey. +func (pk *PublicKey) Marshal() ([]byte, error) { + pkBytes := pk.PointG2.Compressed() + + return pkBytes, nil +} + +// GenerateKeyPair generates BBS+ PublicKey and PrivateKey pair. +func GenerateKeyPair(h func() hash.Hash, seed []byte) (*PublicKey, *PrivateKey, error) { + if len(seed) != 0 && len(seed) != seedSize { + return nil, nil, errors.New("invalid size of seed") + } + + okm, err := generateOKM(seed, h) + if err != nil { + return nil, nil, err + } + + privKeyFr := FrFromOKM(okm) + + privKey := &PrivateKey{privKeyFr} + pubKey := privKey.PublicKey() + + return pubKey, privKey, nil +} + +func generateOKM(ikm []byte, h func() hash.Hash) ([]byte, error) { + salt := []byte(generateKeySalt) + info := make([]byte, 2) + + if ikm != nil { + ikm = append(ikm, 0) + } else { + ikm = make([]byte, seedSize+1) + + _, err := rand.Read(ikm) + if err != nil { + return nil, err + } + + ikm[seedSize] = 0 + } + + return newHKDF(h, ikm, salt, info, frUncompressedSize) +} + +func newHKDF(h func() hash.Hash, ikm, salt, info []byte, length int) ([]byte, error) { + reader := hkdf.New(h, ikm, salt, info) + result := make([]byte, length) + + _, err := io.ReadFull(reader, result) + if err != nil { + return nil, err + } + + return result, nil +} diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/proof_of_knowledge.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/proof_of_knowledge.go new file mode 100644 index 00000000000..eb29f44e08d --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/proof_of_knowledge.go @@ -0,0 +1,230 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package bbs12381g2pub + +import ( + "fmt" + + ml "github.com/IBM/mathlib" +) + +// PoKOfSignature is Proof of Knowledge of a Signature that is used by the prover to construct PoKOfSignatureProof. +type PoKOfSignature struct { + aPrime *ml.G1 + aBar *ml.G1 + d *ml.G1 + + pokVC1 *ProverCommittedG1 + secrets1 []*ml.Zr + + PokVC2 *ProverCommittedG1 + secrets2 []*ml.Zr + + revealedMessages map[int]*SignatureMessage +} + +// NewPoKOfSignature creates a new PoKOfSignature. +func NewPoKOfSignature(signature *Signature, messages []*SignatureMessage, revealedIndexes []int, + pubKey *PublicKeyWithGenerators) (*PoKOfSignature, error) { + err := signature.Verify(messages, pubKey) + if err != nil { + return nil, fmt.Errorf("verify input signature: %w", err) + } + + r1, r2 := createRandSignatureFr(), createRandSignatureFr() + b := computeB(signature.S, messages, pubKey) + aPrime := signature.A.Mul(frToRepr(r1)) + + aBarDenom := aPrime.Mul(frToRepr(signature.E)) + + aBar := b.Mul(frToRepr(r1)) + aBar.Sub(aBarDenom) + + r2D := r2.Copy() + r2D.Neg() + + commitmentBasesCount := 2 + cb := NewCommitmentBuilder(commitmentBasesCount) + cb.Add(b, r1) + cb.Add(pubKey.H0, r2D) + + d := cb.Build() + r3 := r1.Copy() + r3.InvModP(curve.GroupOrder) + + sPrime := r2.Mul(r3) + sPrime.Neg() + sPrime = sPrime.Plus(signature.S) + + pokVC1, secrets1 := newVC1Signature(aPrime, pubKey.H0, signature.E, r2) + + revealedMessages := make(map[int]*SignatureMessage, len(revealedIndexes)) + + if len(messages) < len(revealedIndexes) { + return nil, fmt.Errorf("invalid size: %d revealed indexes is larger than %d messages", len(revealedIndexes), + len(messages)) + } + + for _, ind := range revealedIndexes { + revealedMessages[ind] = messages[ind] + } + + pokVC2, secrets2 := newVC2Signature(d, r3, pubKey, sPrime, messages, revealedMessages) + + return &PoKOfSignature{ + aPrime: aPrime, + aBar: aBar, + d: d, + pokVC1: pokVC1, + secrets1: secrets1, + PokVC2: pokVC2, + secrets2: secrets2, + revealedMessages: revealedMessages, + }, nil +} + +func newVC1Signature(aPrime *ml.G1, h0 *ml.G1, + e, r2 *ml.Zr) (*ProverCommittedG1, []*ml.Zr) { + committing1 := NewProverCommittingG1() + secrets1 := make([]*ml.Zr, 2) + + committing1.Commit(aPrime) + + sigE := e.Copy() + sigE.Neg() + secrets1[0] = sigE + + committing1.Commit(h0) + + secrets1[1] = r2 + pokVC1 := committing1.Finish() + + return pokVC1, secrets1 +} + +func newVC2Signature(d *ml.G1, r3 *ml.Zr, pubKey *PublicKeyWithGenerators, sPrime *ml.Zr, + messages []*SignatureMessage, revealedMessages map[int]*SignatureMessage) (*ProverCommittedG1, []*ml.Zr) { + messagesCount := len(messages) + committing2 := NewProverCommittingG1() + baseSecretsCount := 2 + secrets2 := make([]*ml.Zr, 0, baseSecretsCount+messagesCount) + + committing2.Commit(d) + + r3D := r3.Copy() + r3D.Neg() + + secrets2 = append(secrets2, r3D) + + committing2.Commit(pubKey.H0) + + secrets2 = append(secrets2, sPrime) + + for i := 0; i < messagesCount; i++ { + if _, ok := revealedMessages[i]; ok { + continue + } + + committing2.Commit(pubKey.H[i]) + + sourceFR := messages[i].FR + hiddenFRCopy := sourceFR.Copy() + + secrets2 = append(secrets2, hiddenFRCopy) + } + + pokVC2 := committing2.Finish() + + return pokVC2, secrets2 +} + +// ToBytes converts PoKOfSignature to bytes. +func (pos *PoKOfSignature) ToBytes() []byte { + challengeBytes := pos.aBar.Bytes() + challengeBytes = append(challengeBytes, pos.pokVC1.ToBytes()...) + challengeBytes = append(challengeBytes, pos.PokVC2.ToBytes()...) + + return challengeBytes +} + +// GenerateProof generates PoKOfSignatureProof proof from PoKOfSignature signature. +func (pos *PoKOfSignature) GenerateProof(challengeHash *ml.Zr) *PoKOfSignatureProof { + return &PoKOfSignatureProof{ + aPrime: pos.aPrime, + aBar: pos.aBar, + d: pos.d, + proofVC1: pos.pokVC1.GenerateProof(challengeHash, pos.secrets1), + ProofVC2: pos.PokVC2.GenerateProof(challengeHash, pos.secrets2), + } +} + +// ProverCommittedG1 helps to generate a ProofG1. +type ProverCommittedG1 struct { + Bases []*ml.G1 + BlindingFactors []*ml.Zr + Commitment *ml.G1 +} + +// ToBytes converts ProverCommittedG1 to bytes. +func (g *ProverCommittedG1) ToBytes() []byte { + bytes := make([]byte, 0) + + for _, base := range g.Bases { + bytes = append(bytes, base.Bytes()...) + } + + return append(bytes, g.Commitment.Bytes()...) +} + +// GenerateProof generates proof ProofG1 for all secrets. +func (g *ProverCommittedG1) GenerateProof(challenge *ml.Zr, secrets []*ml.Zr) *ProofG1 { + responses := make([]*ml.Zr, len(g.Bases)) + + for i := range g.BlindingFactors { + c := challenge.Mul(secrets[i]) + + s := g.BlindingFactors[i].Minus(c) + responses[i] = s + } + + return &ProofG1{ + Commitment: g.Commitment, + Responses: responses, + } +} + +// ProverCommittingG1 is a proof of knowledge of messages in a vector commitment. +type ProverCommittingG1 struct { + bases []*ml.G1 + BlindingFactors []*ml.Zr +} + +// NewProverCommittingG1 creates a new ProverCommittingG1. +func NewProverCommittingG1() *ProverCommittingG1 { + return &ProverCommittingG1{ + bases: make([]*ml.G1, 0), + BlindingFactors: make([]*ml.Zr, 0), + } +} + +// Commit append a base point and randomly generated blinding factor. +func (pc *ProverCommittingG1) Commit(base *ml.G1) { + pc.bases = append(pc.bases, base) + r := createRandSignatureFr() + pc.BlindingFactors = append(pc.BlindingFactors, r) +} + +// Finish helps to generate ProverCommittedG1 after commitment of all base points. +func (pc *ProverCommittingG1) Finish() *ProverCommittedG1 { + commitment := sumOfG1Products(pc.bases, pc.BlindingFactors) + + return &ProverCommittedG1{ + Bases: pc.bases, + BlindingFactors: pc.BlindingFactors, + Commitment: commitment, + } +} diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature.go new file mode 100644 index 00000000000..3491e48e424 --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature.go @@ -0,0 +1,70 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package bbs12381g2pub + +import ( + "errors" + "fmt" + + ml "github.com/IBM/mathlib" +) + +// Signature defines BLS signature. +type Signature struct { + A *ml.G1 + E *ml.Zr + S *ml.Zr +} + +// ParseSignature parses a Signature from bytes. +func ParseSignature(sigBytes []byte) (*Signature, error) { + if len(sigBytes) != bls12381SignatureLen { + return nil, errors.New("invalid size of signature") + } + + pointG1, err := curve.NewG1FromCompressed(sigBytes[:g1CompressedSize]) + if err != nil { + return nil, fmt.Errorf("deserialize G1 compressed signature: %w", err) + } + + e := parseFr(sigBytes[g1CompressedSize : g1CompressedSize+frCompressedSize]) + s := parseFr(sigBytes[g1CompressedSize+frCompressedSize:]) + + return &Signature{ + A: pointG1, + E: e, + S: s, + }, nil +} + +// ToBytes converts signature to bytes using compression of G1 point and E, S FR points. +func (s *Signature) ToBytes() ([]byte, error) { + bytes := make([]byte, bls12381SignatureLen) + + copy(bytes, s.A.Compressed()) + copy(bytes[g1CompressedSize:g1CompressedSize+frCompressedSize], s.E.Bytes()) + copy(bytes[g1CompressedSize+frCompressedSize:], s.S.Bytes()) + + return bytes, nil +} + +// Verify is used for signature verification. +func (s *Signature) Verify(messages []*SignatureMessage, pubKey *PublicKeyWithGenerators) error { + p1 := s.A + + q1 := curve.GenG2.Mul(frToRepr(s.E)) + q1.Add(pubKey.w) + + p2 := computeB(s.S, messages, pubKey) + p2.Neg() + + if compareTwoPairings(p1, q1, p2, curve.GenG2) { + return nil + } + + return errors.New("invalid BLS12-381 signature") +} diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_message.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_message.go new file mode 100644 index 00000000000..ec8d9cd196c --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_message.go @@ -0,0 +1,27 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package bbs12381g2pub + +import ( + ml "github.com/IBM/mathlib" +) + +// SignatureMessage defines a message to be used for a signature check. +type SignatureMessage struct { + FR *ml.Zr + Idx int +} + +// ParseSignatureMessage parses SignatureMessage from bytes. +func ParseSignatureMessage(message []byte, idx int) *SignatureMessage { + elm := FrFromOKM(message) + + return &SignatureMessage{ + FR: elm, + Idx: idx, + } +} diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_proof.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_proof.go new file mode 100644 index 00000000000..3a13079ef95 --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/signature_proof.go @@ -0,0 +1,276 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package bbs12381g2pub + +import ( + "encoding/binary" + "errors" + "fmt" + + ml "github.com/IBM/mathlib" +) + +// PoKOfSignatureProof defines BLS signature proof. +// It is the actual proof that is sent from prover to verifier. +type PoKOfSignatureProof struct { + aPrime *ml.G1 + aBar *ml.G1 + d *ml.G1 + + proofVC1 *ProofG1 + ProofVC2 *ProofG1 +} + +// GetBytesForChallenge creates bytes for proof challenge. +func (sp *PoKOfSignatureProof) GetBytesForChallenge(revealedMessages map[int]*SignatureMessage, + pubKey *PublicKeyWithGenerators) []byte { + hiddenCount := pubKey.messagesCount - len(revealedMessages) + + bytesLen := (7 + hiddenCount) * g1UncompressedSize //nolint:gomnd + bytes := make([]byte, 0, bytesLen) + + bytes = append(bytes, sp.aBar.Bytes()...) + bytes = append(bytes, sp.aPrime.Bytes()...) + bytes = append(bytes, pubKey.H0.Bytes()...) + bytes = append(bytes, sp.proofVC1.Commitment.Bytes()...) + bytes = append(bytes, sp.d.Bytes()...) + bytes = append(bytes, pubKey.H0.Bytes()...) + + for i := range pubKey.H { + if _, ok := revealedMessages[i]; !ok { + bytes = append(bytes, pubKey.H[i].Bytes()...) + } + } + + bytes = append(bytes, sp.ProofVC2.Commitment.Bytes()...) + + return bytes +} + +// Verify verifies PoKOfSignatureProof. +func (sp *PoKOfSignatureProof) Verify(challenge *ml.Zr, pubKey *PublicKeyWithGenerators, + revealedMessages map[int]*SignatureMessage, messages []*SignatureMessage) error { + aBar := sp.aBar.Copy() + aBar.Neg() + + ok := compareTwoPairings(sp.aPrime, pubKey.w, aBar, curve.GenG2) + if !ok { + return errors.New("bad signature") + } + + err := sp.verifyVC1Proof(challenge, pubKey) + if err != nil { + return err + } + + return sp.verifyVC2Proof(challenge, pubKey, revealedMessages, messages) +} + +func (sp *PoKOfSignatureProof) verifyVC1Proof(challenge *ml.Zr, pubKey *PublicKeyWithGenerators) error { + basesVC1 := []*ml.G1{sp.aPrime, pubKey.H0} + aBarD := sp.aBar.Copy() + aBarD.Sub(sp.d) + + err := sp.proofVC1.Verify(basesVC1, aBarD, challenge) + if err != nil { + return errors.New("bad signature") + } + + return nil +} + +func (sp *PoKOfSignatureProof) verifyVC2Proof(challenge *ml.Zr, pubKey *PublicKeyWithGenerators, + revealedMessages map[int]*SignatureMessage, messages []*SignatureMessage) error { + revealedMessagesCount := len(revealedMessages) + + basesVC2 := make([]*ml.G1, 0, 2+pubKey.messagesCount-revealedMessagesCount) + basesVC2 = append(basesVC2, sp.d, pubKey.H0) + + basesDisclosed := make([]*ml.G1, 0, 1+revealedMessagesCount) + exponents := make([]*ml.Zr, 0, 1+revealedMessagesCount) + + basesDisclosed = append(basesDisclosed, curve.GenG1) + exponents = append(exponents, curve.NewZrFromInt(1)) + + revealedMessagesInd := 0 + + for i := range pubKey.H { + if _, ok := revealedMessages[i]; ok { + basesDisclosed = append(basesDisclosed, pubKey.H[i]) + exponents = append(exponents, messages[revealedMessagesInd].FR) + revealedMessagesInd++ + } else { + basesVC2 = append(basesVC2, pubKey.H[i]) + } + } + + // TODO: expose 0 + pr := curve.GenG1.Copy() + pr.Sub(curve.GenG1) + + for i := 0; i < len(basesDisclosed); i++ { + b := basesDisclosed[i] + s := exponents[i] + + g := b.Mul(frToRepr(s)) + pr.Add(g) + } + + pr.Neg() + + err := sp.ProofVC2.Verify(basesVC2, pr, challenge) + if err != nil { + return errors.New("bad signature") + } + + return nil +} + +// ToBytes converts PoKOfSignatureProof to bytes. +func (sp *PoKOfSignatureProof) ToBytes() []byte { + bytes := make([]byte, 0) + + bytes = append(bytes, sp.aPrime.Compressed()...) + bytes = append(bytes, sp.aBar.Compressed()...) + bytes = append(bytes, sp.d.Compressed()...) + + proof1Bytes := sp.proofVC1.ToBytes() + lenBytes := make([]byte, 4) + binary.BigEndian.PutUint32(lenBytes, uint32(len(proof1Bytes))) + bytes = append(bytes, lenBytes...) + bytes = append(bytes, proof1Bytes...) + + bytes = append(bytes, sp.ProofVC2.ToBytes()...) + + return bytes +} + +// ProofG1 is a proof of knowledge of a signature and hidden messages. +type ProofG1 struct { + Commitment *ml.G1 + Responses []*ml.Zr +} + +// NewProofG1 creates a new ProofG1. +func NewProofG1(commitment *ml.G1, responses []*ml.Zr) *ProofG1 { + return &ProofG1{ + Commitment: commitment, + Responses: responses, + } +} + +// Verify verifies the ProofG1. +func (pg1 *ProofG1) Verify(bases []*ml.G1, commitment *ml.G1, challenge *ml.Zr) error { + contribution := pg1.getChallengeContribution(bases, commitment, challenge) + contribution.Sub(pg1.Commitment) + + if !contribution.IsInfinity() { + return errors.New("contribution is not zero") + } + + return nil +} + +func (pg1 *ProofG1) getChallengeContribution(bases []*ml.G1, commitment *ml.G1, + challenge *ml.Zr) *ml.G1 { + points := append(bases, commitment) + scalars := append(pg1.Responses, challenge) + + return sumOfG1Products(points, scalars) +} + +// ToBytes converts ProofG1 to bytes. +func (pg1 *ProofG1) ToBytes() []byte { + bytes := make([]byte, 0) + + commitmentBytes := pg1.Commitment.Compressed() + bytes = append(bytes, commitmentBytes...) + + lenBytes := make([]byte, 4) + binary.BigEndian.PutUint32(lenBytes, uint32(len(pg1.Responses))) + bytes = append(bytes, lenBytes...) + + for i := range pg1.Responses { + responseBytes := frToRepr(pg1.Responses[i]).Bytes() + bytes = append(bytes, responseBytes...) + } + + return bytes +} + +// ParseSignatureProof parses a signature proof. +func ParseSignatureProof(sigProofBytes []byte) (*PoKOfSignatureProof, error) { + if len(sigProofBytes) < g1CompressedSize*3 { + return nil, errors.New("invalid size of signature proof") + } + + g1Points := make([]*ml.G1, 3) + offset := 0 + + for i := range g1Points { + g1Point, err := curve.NewG1FromCompressed(sigProofBytes[offset : offset+g1CompressedSize]) + if err != nil { + return nil, fmt.Errorf("parse G1 point: %w", err) + } + + g1Points[i] = g1Point + offset += g1CompressedSize + } + + proof1BytesLen := int(uint32FromBytes(sigProofBytes[offset : offset+4])) + offset += 4 + + proofVc1, err := ParseProofG1(sigProofBytes[offset : offset+proof1BytesLen]) + if err != nil { + return nil, fmt.Errorf("parse G1 proof: %w", err) + } + + offset += proof1BytesLen + + proofVc2, err := ParseProofG1(sigProofBytes[offset:]) + if err != nil { + return nil, fmt.Errorf("parse G1 proof: %w", err) + } + + return &PoKOfSignatureProof{ + aPrime: g1Points[0], + aBar: g1Points[1], + d: g1Points[2], + proofVC1: proofVc1, + ProofVC2: proofVc2, + }, nil +} + +// ParseProofG1 parses ProofG1 from bytes. +func ParseProofG1(bytes []byte) (*ProofG1, error) { + if len(bytes) < g1CompressedSize+4 { + return nil, errors.New("invalid size of G1 signature proof") + } + + offset := 0 + + commitment, err := curve.NewG1FromCompressed(bytes[:g1CompressedSize]) + if err != nil { + return nil, fmt.Errorf("parse G1 point: %w", err) + } + + offset += g1CompressedSize + length := int(uint32FromBytes(bytes[offset : offset+4])) + offset += 4 + + if len(bytes) < g1CompressedSize+4+length*frCompressedSize { + return nil, errors.New("invalid size of G1 signature proof") + } + + responses := make([]*ml.Zr, length) + for i := 0; i < length; i++ { + responses[i] = parseFr(bytes[offset : offset+frCompressedSize]) + offset += frCompressedSize + } + + return NewProofG1(commitment, responses), nil +} diff --git a/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/utils.go b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/utils.go new file mode 100644 index 00000000000..8bcb3430567 --- /dev/null +++ b/vendor/github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub/utils.go @@ -0,0 +1,125 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package bbs12381g2pub + +import ( + "encoding/binary" + "errors" +) + +func uint32ToBytes(value uint32) []byte { + bytes := make([]byte, 4) + + binary.BigEndian.PutUint32(bytes, value) + + return bytes +} + +func uint16FromBytes(bytes []byte) uint16 { + return binary.BigEndian.Uint16(bytes) +} + +func uint32FromBytes(bytes []byte) uint32 { + return binary.BigEndian.Uint32(bytes) +} + +func bitvectorToIndexes(data []byte) []int { + revealedIndexes := make([]int, 0) + scalar := 0 + + for _, v := range data { + remaining := 8 + + for v > 0 { + revealed := v & 1 + if revealed == 1 { + revealedIndexes = append(revealedIndexes, scalar) + } + + v >>= 1 + scalar++ + remaining-- + } + + scalar += remaining + } + + return revealedIndexes +} + +type pokPayload struct { + messagesCount int + Revealed []int +} + +// nolint:gomnd +func ParsePoKPayload(bytes []byte) (*pokPayload, error) { + if len(bytes) < 2 { + return nil, errors.New("invalid size of PoK payload") + } + + messagesCount := int(uint16FromBytes(bytes[0:2])) + offset := lenInBytes(messagesCount) + + if len(bytes) < offset { + return nil, errors.New("invalid size of PoK payload") + } + + revealed := bitvectorToIndexes(reverseBytes(bytes[2:offset])) + + return &pokPayload{ + messagesCount: messagesCount, + Revealed: revealed, + }, nil +} + +// nolint:gomnd +func (p *pokPayload) ToBytes() ([]byte, error) { + bytes := make([]byte, p.LenInBytes()) + + binary.BigEndian.PutUint16(bytes, uint16(p.messagesCount)) + + bitvector := bytes[2:] + + for _, r := range p.Revealed { + idx := r / 8 + bit := r % 8 + + if len(bitvector) <= idx { + return nil, errors.New("invalid size of PoK payload") + } + + bitvector[idx] |= 1 << bit + } + + reverseBytes(bitvector) + + return bytes, nil +} + +func (p *pokPayload) LenInBytes() int { + return lenInBytes(p.messagesCount) +} + +func lenInBytes(messagesCount int) int { + return 2 + (messagesCount / 8) + 1 //nolint:gomnd +} + +func NewPoKPayload(messagesCount int, revealed []int) *pokPayload { + return &pokPayload{ + messagesCount: messagesCount, + Revealed: revealed, + } +} + +func reverseBytes(s []byte) []byte { + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } + + return s +} diff --git a/vendor/github.com/bits-and-blooms/bitset/README.md b/vendor/github.com/bits-and-blooms/bitset/README.md index 97e83071e41..fe7bca65ebb 100644 --- a/vendor/github.com/bits-and-blooms/bitset/README.md +++ b/vendor/github.com/bits-and-blooms/bitset/README.md @@ -7,6 +7,15 @@ [![PkgGoDev](https://pkg.go.dev/badge/github.com/bits-and-blooms/bitset?tab=doc)](https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc) +This library is part of the [awesome go collection](https://github.com/avelino/awesome-go). It is used in production by several important systems: + +* [beego](https://github.com/beego/beego) +* [CubeFS](https://github.com/cubefs/cubefs) +* [Amazon EKS Distro](https://github.com/aws/eks-distro) +* [sourcegraph](https://github.com/sourcegraph/sourcegraph) +* [torrent](https://github.com/anacrolix/torrent) + + ## Description Package bitset implements bitsets, a mapping between non-negative integers and boolean values. @@ -60,19 +69,76 @@ func main() { } ``` -As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets. Package documentation is at: https://pkg.go.dev/github.com/bits-and-blooms/bitset?tab=doc +## Serialization + + +You may serialize a bitset safely and portably to a stream +of bytes as follows: +```Go + const length = 9585 + const oneEvery = 97 + bs := bitset.New(length) + // Add some bits + for i := uint(0); i < length; i += oneEvery { + bs = bs.Set(i) + } + + var buf bytes.Buffer + n, err := bs.WriteTo(&buf) + if err != nil { + // failure + } + // Here n == buf.Len() +``` +You can later deserialize the result as follows: + +```Go + // Read back from buf + bs = bitset.New() + n, err = bs.ReadFrom(&buf) + if err != nil { + // error + } + // n is the number of bytes read +``` + +The `ReadFrom` function attempts to read the data into the existing +BitSet instance, to minimize memory allocations. + + +*Performance tip*: +When reading and writing to a file or a network connection, you may get better performance by +wrapping your streams with `bufio` instances. + +E.g., +```Go + f, err := os.Create("myfile") + w := bufio.NewWriter(f) +``` +```Go + f, err := os.Open("myfile") + r := bufio.NewReader(f) +``` + ## Memory Usage -The memory usage of a bitset using N bits is at least N/8 bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). +The memory usage of a bitset using `N` bits is at least `N/8` bytes. The number of bits in a bitset is at least as large as one plus the greatest bit index you have accessed. Thus it is possible to run out of memory while using a bitset. If you have lots of bits, you might prefer compressed bitsets, like the [Roaring bitmaps](http://roaringbitmap.org) and its [Go implementation](https://github.com/RoaringBitmap/roaring). + +The `roaring` library allows you to go back and forth between compressed Roaring bitmaps and the conventional bitset instances: +```Go + mybitset := roaringbitmap.ToBitSet() + newroaringbitmap := roaring.FromBitSet(mybitset) +``` + ## Implementation Note Go 1.9 introduced a native `math/bits` library. We provide backward compatibility to Go 1.7, which might be removed. -It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `unit64`). If so, the version will be bumped. +It is possible that a later version will match the `math/bits` return signature for counts (which is `int`, rather than our library's `uint64`). If so, the version will be bumped. ## Installation diff --git a/vendor/github.com/bits-and-blooms/bitset/SECURITY.md b/vendor/github.com/bits-and-blooms/bitset/SECURITY.md new file mode 100644 index 00000000000..f888420c3ba --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +You can report privately a vulnerability by email at daniel@lemire.me (current maintainer). diff --git a/vendor/github.com/bits-and-blooms/bitset/bitset.go b/vendor/github.com/bits-and-blooms/bitset/bitset.go index 271ccdbd0d2..9f38ed3a9dc 100644 --- a/vendor/github.com/bits-and-blooms/bitset/bitset.go +++ b/vendor/github.com/bits-and-blooms/bitset/bitset.go @@ -33,12 +33,10 @@ Example use: As an alternative to BitSets, one should check out the 'big' package, which provides a (less set-theoretical) view of bitsets. - */ package bitset import ( - "bufio" "bytes" "encoding/base64" "encoding/binary" @@ -52,6 +50,9 @@ import ( // the wordSize of a bit set const wordSize = uint(64) +// the wordSize of a bit set in bytes +const wordBytes = wordSize / 8 + // log2WordSize is lg(wordSize) const log2WordSize = uint(6) @@ -87,12 +88,23 @@ func (b *BitSet) safeSet() []uint64 { return b.set } -// From is a constructor used to create a BitSet from an array of integers +// SetBitsetFrom fills the bitset with an array of integers without creating a new BitSet instance +func (b *BitSet) SetBitsetFrom(buf []uint64) { + b.length = uint(len(buf)) * 64 + b.set = buf +} + +// From is a constructor used to create a BitSet from an array of words func From(buf []uint64) *BitSet { - return &BitSet{uint(len(buf)) * 64, buf} + return FromWithLength(uint(len(buf))*64, buf) } -// Bytes returns the bitset as array of integers +// FromWithLength constructs from an array of words and length. +func FromWithLength(len uint, set []uint64) *BitSet { + return &BitSet{len, set} +} + +// Bytes returns the bitset as array of words func (b *BitSet) Bytes() []uint64 { return b.set } @@ -105,6 +117,17 @@ func wordsNeeded(i uint) int { return int((i + (wordSize - 1)) >> log2WordSize) } +// wordsNeededUnbound calculates the number of words needed for i bits, possibly exceeding the capacity. +// This function is useful if you know that the capacity cannot be exceeded (e.g., you have an existing bitmap). +func wordsNeededUnbound(i uint) int { + return int((i + (wordSize - 1)) >> log2WordSize) +} + +// wordsIndex calculates the index of words in a `uint64` +func wordsIndex(i uint) uint { + return i & (wordSize - 1) +} + // New creates a new BitSet with a hint that length bits will be required func New(length uint) (bset *BitSet) { defer func() { @@ -135,24 +158,22 @@ func (b *BitSet) Len() uint { return b.length } -// extendSetMaybe adds additional words to incorporate new bits if needed -func (b *BitSet) extendSetMaybe(i uint) { - if i >= b.length { // if we need more bits, make 'em - if i >= Cap() { - panic("You are exceeding the capacity") - } - nsize := wordsNeeded(i + 1) - if b.set == nil { - b.set = make([]uint64, nsize) - } else if cap(b.set) >= nsize { - b.set = b.set[:nsize] // fast resize - } else if len(b.set) < nsize { - newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x - copy(newset, b.set) - b.set = newset - } - b.length = i + 1 +// extendSet adds additional words to incorporate new bits if needed +func (b *BitSet) extendSet(i uint) { + if i >= Cap() { + panic("You are exceeding the capacity") } + nsize := wordsNeeded(i + 1) + if b.set == nil { + b.set = make([]uint64, nsize) + } else if cap(b.set) >= nsize { + b.set = b.set[:nsize] // fast resize + } else if len(b.set) < nsize { + newset := make([]uint64, nsize, 2*nsize) // increase capacity 2x + copy(newset, b.set) + b.set = newset + } + b.length = i + 1 } // Test whether bit i is set. @@ -160,7 +181,7 @@ func (b *BitSet) Test(i uint) bool { if i >= b.length { return false } - return b.set[i>>log2WordSize]&(1<<(i&(wordSize-1))) != 0 + return b.set[i>>log2WordSize]&(1<>log2WordSize] |= 1 << (i & (wordSize - 1)) + if i >= b.length { // if we need more bits, make 'em + b.extendSet(i) + } + b.set[i>>log2WordSize] |= 1 << wordsIndex(i) return b } @@ -180,7 +203,7 @@ func (b *BitSet) Clear(i uint) *BitSet { if i >= b.length { return b } - b.set[i>>log2WordSize] &^= 1 << (i & (wordSize - 1)) + b.set[i>>log2WordSize] &^= 1 << wordsIndex(i) return b } @@ -205,7 +228,7 @@ func (b *BitSet) Flip(i uint) *BitSet { if i >= b.length { return b.Set(i) } - b.set[i>>log2WordSize] ^= 1 << (i & (wordSize - 1)) + b.set[i>>log2WordSize] ^= 1 << wordsIndex(i) return b } @@ -218,15 +241,23 @@ func (b *BitSet) FlipRange(start, end uint) *BitSet { if start >= end { return b } - - b.extendSetMaybe(end - 1) + if end-1 >= b.length { // if we need more bits, make 'em + b.extendSet(end - 1) + } var startWord uint = start >> log2WordSize var endWord uint = end >> log2WordSize - b.set[startWord] ^= ^(^uint64(0) << (start & (wordSize - 1))) - for i := startWord; i < endWord; i++ { - b.set[i] = ^b.set[i] + b.set[startWord] ^= ^(^uint64(0) << wordsIndex(start)) + if endWord > 0 { + // bounds check elimination + data := b.set + _ = data[endWord-1] + for i := startWord; i < endWord; i++ { + data[i] = ^data[i] + } + } + if end&(wordSize-1) != 0 { + b.set[endWord] ^= ^uint64(0) >> wordsIndex(-end) } - b.set[endWord] ^= ^uint64(0) >> (-end & (wordSize - 1)) return b } @@ -254,9 +285,10 @@ func (b *BitSet) Shrink(lastbitindex uint) *BitSet { copy(shrunk, b.set[:idx]) b.set = shrunk b.length = length - if length < 64 { - b.set[idx-1] &= (allBits >> (uint64(64) - uint64(length&(wordSize-1)))) - } + lastWordUsedBits := length % 64 + if lastWordUsedBits != 0 { + b.set[idx-1] &= allBits >> uint64(64-wordsIndex(lastWordUsedBits)) + } return b } @@ -285,7 +317,7 @@ func (b *BitSet) Compact() *BitSet { // this method could be extremely slow and in some cases might cause the entire BitSet // to be recopied. func (b *BitSet) InsertAt(idx uint) *BitSet { - insertAtElement := (idx >> log2WordSize) + insertAtElement := idx >> log2WordSize // if length of set is a multiple of wordSize we need to allocate more space first if b.isLenExactMultiple() { @@ -304,13 +336,13 @@ func (b *BitSet) InsertAt(idx uint) *BitSet { // generate a mask to extract the data that we need to shift left // within the element where we insert a bit - dataMask := ^(uint64(1)<> (i & (wordSize - 1)) + w = w >> wordsIndex(i) if w != 0 { return i + trailingZeroes64(w), true } - x = x + 1 + x++ + // bounds check elimination in the loop + if x < 0 { + return 0, false + } for x < len(b.set) { if b.set[x] != 0 { return uint(x)*wordSize + trailingZeroes64(b.set[x]), true } - x = x + 1 + x++ } return 0, false @@ -415,21 +451,20 @@ func (b *BitSet) NextSet(i uint) (uint, bool) { // including possibly the current index and up to cap(buffer). // If the returned slice has len zero, then no more set bits were found // -// buffer := make([]uint, 256) // this should be reused -// j := uint(0) -// j, buffer = bitmap.NextSetMany(j, buffer) -// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) { -// for k := range buffer { -// do something with buffer[k] -// } -// j += 1 -// } -// +// buffer := make([]uint, 256) // this should be reused +// j := uint(0) +// j, buffer = bitmap.NextSetMany(j, buffer) +// for ; len(buffer) > 0; j, buffer = bitmap.NextSetMany(j,buffer) { +// for k := range buffer { +// do something with buffer[k] +// } +// j += 1 +// } // // It is possible to retrieve all set bits as follow: // -// indices := make([]uint, bitmap.Count()) -// bitmap.NextSetMany(0, indices) +// indices := make([]uint, bitmap.Count()) +// bitmap.NextSetMany(0, indices) // // However if bitmap.Count() is large, it might be preferable to // use several calls to NextSetMany, for performance reasons. @@ -440,7 +475,7 @@ func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { if x >= len(b.set) || capacity == 0 { return 0, myanswer[:0] } - skip := i & (wordSize - 1) + skip := wordsIndex(i) word := b.set[x] >> skip myanswer = myanswer[:capacity] size := int(0) @@ -483,17 +518,23 @@ func (b *BitSet) NextClear(i uint) (uint, bool) { return 0, false } w := b.set[x] - w = w >> (i & (wordSize - 1)) - wA := allBits >> (i & (wordSize - 1)) + w = w >> wordsIndex(i) + wA := allBits >> wordsIndex(i) index := i + trailingZeroes64(^w) if w != wA && index < b.length { return index, true } x++ + // bounds check elimination in the loop + if x < 0 { + return 0, false + } for x < len(b.set) { - index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) - if b.set[x] != allBits && index < b.length { - return index, true + if b.set[x] != allBits { + index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) + if index < b.length { + return index, true + } } x++ } @@ -510,9 +551,21 @@ func (b *BitSet) ClearAll() *BitSet { return b } +// SetAll sets the entire BitSet +func (b *BitSet) SetAll() *BitSet { + if b != nil && b.set != nil { + for i := range b.set { + b.set[i] = allBits + } + + b.cleanLastWord() + } + return b +} + // wordCount returns the number of words used in a bit set func (b *BitSet) wordCount() int { - return len(b.set) + return wordsNeededUnbound(b.length) } // Clone this BitSet @@ -524,9 +577,10 @@ func (b *BitSet) Clone() *BitSet { return c } -// Copy into a destination BitSet -// Returning the size of the destination BitSet -// like array copy +// Copy into a destination BitSet using the Go array copy semantics: +// the number of bits copied is the minimum of the number of bits in the current +// BitSet (Len()) and the destination Bitset. +// We return the number of bits copied in the destination BitSet. func (b *BitSet) Copy(c *BitSet) (count uint) { if c == nil { return @@ -538,9 +592,33 @@ func (b *BitSet) Copy(c *BitSet) (count uint) { if b.length < c.length { count = b.length } + // Cleaning the last word is needed to keep the invariant that other functions, such as Count, require + // that any bits in the last word that would exceed the length of the bitmask are set to 0. + c.cleanLastWord() return } +// CopyFull copies into a destination BitSet such that the destination is +// identical to the source after the operation, allocating memory if necessary. +func (b *BitSet) CopyFull(c *BitSet) { + if c == nil { + return + } + c.length = b.length + if len(b.set) == 0 { + if c.set != nil { + c.set = c.set[:0] + } + } else { + if cap(c.set) < len(b.set) { + c.set = make([]uint64, len(b.set)) + } else { + c.set = c.set[:len(b.set)] + } + copy(c.set, b.set) + } +} + // Count (number of set bits). // Also known as "popcount" or "population count". func (b *BitSet) Count() uint { @@ -563,10 +641,15 @@ func (b *BitSet) Equal(c *BitSet) bool { if b.length == 0 { // if they have both length == 0, then could have nil set return true } - // testing for equality shoud not transform the bitset (no call to safeSet) - - for p, v := range b.set { - if c.set[p] != v { + wn := b.wordCount() + // bounds check elimination + if wn <= 0 { + return true + } + _ = b.set[wn-1] + _ = c.set[wn-1] + for p := 0; p < wn; p++ { + if c.set[p] != b.set[p] { return false } } @@ -585,9 +668,9 @@ func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { panicIfNull(b) panicIfNull(compare) result = b.Clone() // clone b (in case b is bigger than compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) + l := compare.wordCount() + if l > b.wordCount() { + l = b.wordCount() } for i := 0; i < l; i++ { result.set[i] = b.set[i] &^ compare.set[i] @@ -599,9 +682,9 @@ func (b *BitSet) Difference(compare *BitSet) (result *BitSet) { func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { panicIfNull(b) panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) + l := compare.wordCount() + if l > b.wordCount() { + l = b.wordCount() } cnt := uint64(0) cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) @@ -614,12 +697,19 @@ func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceDifference(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) + l := compare.wordCount() + if l > b.wordCount() { + l = b.wordCount() + } + if l <= 0 { + return } + // bounds check elimination + data, cmpData := b.set, compare.set + _ = data[l-1] + _ = cmpData[l-1] for i := 0; i < l; i++ { - b.set[i] &^= compare.set[i] + data[i] &^= cmpData[i] } } @@ -662,18 +752,29 @@ func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceIntersection(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - for i := 0; i < l; i++ { - b.set[i] &= compare.set[i] + l := compare.wordCount() + if l > b.wordCount() { + l = b.wordCount() + } + if l > 0 { + // bounds check elimination + data, cmpData := b.set, compare.set + _ = data[l-1] + _ = cmpData[l-1] + + for i := 0; i < l; i++ { + data[i] &= cmpData[i] + } } - for i := l; i < len(b.set); i++ { - b.set[i] = 0 + if l >= 0 { + for i := l; i < len(b.set); i++ { + b.set[i] = 0 + } } if compare.length > 0 { - b.extendSetMaybe(compare.length - 1) + if compare.length-1 >= b.length { + b.extendSet(compare.length - 1) + } } } @@ -708,15 +809,22 @@ func (b *BitSet) UnionCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceUnion(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) + l := compare.wordCount() + if l > b.wordCount() { + l = b.wordCount() } - if compare.length > 0 { - b.extendSetMaybe(compare.length - 1) + if compare.length > 0 && compare.length-1 >= b.length { + b.extendSet(compare.length - 1) } - for i := 0; i < l; i++ { - b.set[i] |= compare.set[i] + if l > 0 { + // bounds check elimination + data, cmpData := b.set, compare.set + _ = data[l-1] + _ = cmpData[l-1] + + for i := 0; i < l; i++ { + data[i] |= cmpData[i] + } } if len(compare.set) > l { for i := l; i < len(compare.set); i++ { @@ -756,15 +864,21 @@ func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { panicIfNull(b) panicIfNull(compare) - l := int(compare.wordCount()) - if l > int(b.wordCount()) { - l = int(b.wordCount()) - } - if compare.length > 0 { - b.extendSetMaybe(compare.length - 1) - } - for i := 0; i < l; i++ { - b.set[i] ^= compare.set[i] + l := compare.wordCount() + if l > b.wordCount() { + l = b.wordCount() + } + if compare.length > 0 && compare.length-1 >= b.length { + b.extendSet(compare.length - 1) + } + if l > 0 { + // bounds check elimination + data, cmpData := b.set, compare.set + _ = data[l-1] + _ = cmpData[l-1] + for i := 0; i < l; i++ { + data[i] ^= cmpData[i] + } } if len(compare.set) > l { for i := l; i < len(compare.set); i++ { @@ -775,17 +889,17 @@ func (b *BitSet) InPlaceSymmetricDifference(compare *BitSet) { // Is the length an exact multiple of word sizes? func (b *BitSet) isLenExactMultiple() bool { - return b.length%wordSize == 0 + return wordsIndex(b.length) == 0 } // Clean last word by setting unused bits to 0 func (b *BitSet) cleanLastWord() { if !b.isLenExactMultiple() { - b.set[len(b.set)-1] &= allBits >> (wordSize - b.length%wordSize) + b.set[len(b.set)-1] &= allBits >> (wordSize - wordsIndex(b.length)) } } -// Complement computes the (local) complement of a biset (up to length bits) +// Complement computes the (local) complement of a bitset (up to length bits) func (b *BitSet) Complement() (result *BitSet) { panicIfNull(b) result = New(b.length) @@ -813,7 +927,6 @@ func (b *BitSet) None() bool { return false } } - return true } return true } @@ -826,12 +939,16 @@ func (b *BitSet) Any() bool { // IsSuperSet returns true if this is a superset of the other set func (b *BitSet) IsSuperSet(other *BitSet) bool { - for i, e := other.NextSet(0); e; i, e = other.NextSet(i + 1) { - if !b.Test(i) { + l := other.wordCount() + if b.wordCount() < l { + l = b.wordCount() + } + for i, word := range other.set[:l] { + if b.set[i]&word != word { return false } } - return true + return popcntSlice(other.set[l:]) == 0 } // IsStrictSuperSet returns true if this is a strict superset of the other set @@ -839,7 +956,8 @@ func (b *BitSet) IsStrictSuperSet(other *BitSet) bool { return b.Count() > other.Count() && b.IsSuperSet(other) } -// DumpAsBits dumps a bit set as a string of bits +// DumpAsBits dumps a bit set as a string of bits. Following the usual convention in Go, +// the least significant bits are printed last (index 0 is at the end of the string). func (b *BitSet) DumpAsBits() string { if b.set == nil { return "." @@ -852,78 +970,156 @@ func (b *BitSet) DumpAsBits() string { return buffer.String() } -// BinaryStorageSize returns the binary storage requirements +// BinaryStorageSize returns the binary storage requirements (see WriteTo) in bytes. func (b *BitSet) BinaryStorageSize() int { - return binary.Size(uint64(0)) + binary.Size(b.set) + return int(wordBytes + wordBytes*uint(b.wordCount())) } -// WriteTo writes a BitSet to a stream +func readUint64Array(reader io.Reader, data []uint64) error { + length := len(data) + bufferSize := 128 + buffer := make([]byte, bufferSize*int(wordBytes)) + for i := 0; i < length; i += bufferSize { + end := i + bufferSize + if end > length { + end = length + buffer = buffer[:wordBytes*uint(end-i)] + } + chunk := data[i:end] + if _, err := io.ReadFull(reader, buffer); err != nil { + return err + } + for i := range chunk { + chunk[i] = uint64(binaryOrder.Uint64(buffer[8*i:])) + } + } + return nil +} + +func writeUint64Array(writer io.Writer, data []uint64) error { + bufferSize := 128 + buffer := make([]byte, bufferSize*int(wordBytes)) + for i := 0; i < len(data); i += bufferSize { + end := i + bufferSize + if end > len(data) { + end = len(data) + buffer = buffer[:wordBytes*uint(end-i)] + } + chunk := data[i:end] + for i, x := range chunk { + binaryOrder.PutUint64(buffer[8*i:], x) + } + _, err := writer.Write(buffer) + if err != nil { + return err + } + } + return nil +} + +// WriteTo writes a BitSet to a stream. The format is: +// 1. uint64 length +// 2. []uint64 set +// Upon success, the number of bytes written is returned. +// +// Performance: if this function is used to write to a disk or network +// connection, it might be beneficial to wrap the stream in a bufio.Writer. +// E.g., +// +// f, err := os.Create("myfile") +// w := bufio.NewWriter(f) func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { length := uint64(b.length) - // Write length - err := binary.Write(stream, binaryOrder, length) + err := binary.Write(stream, binaryOrder, &length) if err != nil { - return 0, err + // Upon failure, we do not guarantee that we + // return the number of bytes written. + return int64(0), err } - - // Write set - err = binary.Write(stream, binaryOrder, b.set) - return int64(b.BinaryStorageSize()), err + err = writeUint64Array(stream, b.set[:b.wordCount()]) + if err != nil { + // Upon failure, we do not guarantee that we + // return the number of bytes written. + return int64(wordBytes), err + } + return int64(b.BinaryStorageSize()), nil } // ReadFrom reads a BitSet from a stream written using WriteTo +// The format is: +// 1. uint64 length +// 2. []uint64 set +// Upon success, the number of bytes read is returned. +// If the current BitSet is not large enough to hold the data, +// it is extended. In case of error, the BitSet is either +// left unchanged or made empty if the error occurs too late +// to preserve the content. +// +// Performance: if this function is used to read from a disk or network +// connection, it might be beneficial to wrap the stream in a bufio.Reader. +// E.g., +// +// f, err := os.Open("myfile") +// r := bufio.NewReader(f) func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { var length uint64 - - // Read length first err := binary.Read(stream, binaryOrder, &length) if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } return 0, err } - newset := New(uint(length)) + newlength := uint(length) - if uint64(newset.length) != length { + if uint64(newlength) != length { return 0, errors.New("unmarshalling error: type mismatch") } + nWords := wordsNeeded(uint(newlength)) + if cap(b.set) >= nWords { + b.set = b.set[:nWords] + } else { + b.set = make([]uint64, nWords) + } + + b.length = newlength - // Read remaining bytes as set - err = binary.Read(stream, binaryOrder, newset.set) + err = readUint64Array(stream, b.set) if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + // We do not want to leave the BitSet partially filled as + // it is error prone. + b.set = b.set[:0] + b.length = 0 return 0, err } - *b = *newset return int64(b.BinaryStorageSize()), nil } // MarshalBinary encodes a BitSet into a binary form and returns the result. func (b *BitSet) MarshalBinary() ([]byte, error) { var buf bytes.Buffer - writer := bufio.NewWriter(&buf) - - _, err := b.WriteTo(writer) + _, err := b.WriteTo(&buf) if err != nil { return []byte{}, err } - err = writer.Flush() - return buf.Bytes(), err } // UnmarshalBinary decodes the binary form generated by MarshalBinary. func (b *BitSet) UnmarshalBinary(data []byte) error { buf := bytes.NewReader(data) - reader := bufio.NewReader(buf) - - _, err := b.ReadFrom(reader) - + _, err := b.ReadFrom(buf) return err } // MarshalJSON marshals a BitSet as a JSON structure -func (b *BitSet) MarshalJSON() ([]byte, error) { +func (b BitSet) MarshalJSON() ([]byte, error) { buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) _, err := b.WriteTo(buffer) if err != nil { @@ -952,3 +1148,37 @@ func (b *BitSet) UnmarshalJSON(data []byte) error { _, err = b.ReadFrom(bytes.NewReader(buf)) return err } + +// Rank returns the nunber of set bits up to and including the index +// that are set in the bitset. +// See https://en.wikipedia.org/wiki/Ranking#Ranking_in_statistics +func (b *BitSet) Rank(index uint) uint { + if index >= b.length { + return b.Count() + } + leftover := (index + 1) & 63 + answer := uint(popcntSlice(b.set[:(index+1)>>6])) + if leftover != 0 { + answer += uint(popcount(b.set[(index+1)>>6] << (64 - leftover))) + } + return answer +} + +// Select returns the index of the jth set bit, where j is the argument. +// The caller is responsible to ensure that 0 <= j < Count(): when j is +// out of range, the function returns the length of the bitset (b.length). +// +// Note that this function differs in convention from the Rank function which +// returns 1 when ranking the smallest value. We follow the conventional +// textbook definition of Select and Rank. +func (b *BitSet) Select(index uint) uint { + leftover := index + for idx, word := range b.set { + w := uint(popcount(word)) + if w > leftover { + return uint(idx)*64 + select64(word, leftover) + } + leftover -= w + } + return b.length +} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go index fc8ff4f367c..7855c04b5b2 100644 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go @@ -1,3 +1,4 @@ +//go:build go1.9 // +build go1.9 package bitset @@ -14,6 +15,10 @@ func popcntSlice(s []uint64) uint64 { func popcntMaskSlice(s, m []uint64) uint64 { var cnt int + // this explicit check eliminates a bounds check in the loop + if len(m) < len(s) { + panic("mask slice is too short") + } for i := range s { cnt += bits.OnesCount64(s[i] &^ m[i]) } @@ -22,6 +27,10 @@ func popcntMaskSlice(s, m []uint64) uint64 { func popcntAndSlice(s, m []uint64) uint64 { var cnt int + // this explicit check eliminates a bounds check in the loop + if len(m) < len(s) { + panic("mask slice is too short") + } for i := range s { cnt += bits.OnesCount64(s[i] & m[i]) } @@ -30,6 +39,10 @@ func popcntAndSlice(s, m []uint64) uint64 { func popcntOrSlice(s, m []uint64) uint64 { var cnt int + // this explicit check eliminates a bounds check in the loop + if len(m) < len(s) { + panic("mask slice is too short") + } for i := range s { cnt += bits.OnesCount64(s[i] | m[i]) } @@ -38,6 +51,10 @@ func popcntOrSlice(s, m []uint64) uint64 { func popcntXorSlice(s, m []uint64) uint64 { var cnt int + // this explicit check eliminates a bounds check in the loop + if len(m) < len(s) { + panic("mask slice is too short") + } for i := range s { cnt += bits.OnesCount64(s[i] ^ m[i]) } diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go index 4cf64f24ad0..116e044407c 100644 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go @@ -1,5 +1,5 @@ -// +build !go1.9 -// +build amd64,!appengine +//go:build !go1.9 && amd64 && !appengine +// +build !go1.9,amd64,!appengine package bitset diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go index 21e0ff7b4fc..9e0ad464e09 100644 --- a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go @@ -1,3 +1,4 @@ +//go:build !go1.9 && (!amd64 || appengine) // +build !go1.9 // +build !amd64 appengine diff --git a/vendor/github.com/bits-and-blooms/bitset/select.go b/vendor/github.com/bits-and-blooms/bitset/select.go new file mode 100644 index 00000000000..f15e74a2c9e --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/select.go @@ -0,0 +1,45 @@ +package bitset + +func select64(w uint64, j uint) uint { + seen := 0 + // Divide 64bit + part := w & 0xFFFFFFFF + n := uint(popcount(part)) + if n <= j { + part = w >> 32 + seen += 32 + j -= n + } + ww := part + + // Divide 32bit + part = ww & 0xFFFF + + n = uint(popcount(part)) + if n <= j { + part = ww >> 16 + seen += 16 + j -= n + } + ww = part + + // Divide 16bit + part = ww & 0xFF + n = uint(popcount(part)) + if n <= j { + part = ww >> 8 + seen += 8 + j -= n + } + ww = part + + // Lookup in final byte + counter := 0 + for ; counter < 8; counter++ { + j -= uint((ww >> counter) & 1) + if j+1 == 0 { + break + } + } + return uint(seen + counter) +} diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go index c52b61be9fc..12336e76af3 100644 --- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go +++ b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go @@ -1,3 +1,4 @@ +//go:build !go1.9 // +build !go1.9 package bitset diff --git a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go index 36a988e714d..cfb0a840910 100644 --- a/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go +++ b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go @@ -1,3 +1,4 @@ +//go:build go1.9 // +build go1.9 package bitset diff --git a/vendor/github.com/consensys/bavard/.gitignore b/vendor/github.com/consensys/bavard/.gitignore new file mode 100644 index 00000000000..4a3d4858e0f --- /dev/null +++ b/vendor/github.com/consensys/bavard/.gitignore @@ -0,0 +1,2 @@ + +.idea/* \ No newline at end of file diff --git a/vendor/github.com/consensys/bavard/LICENSE b/vendor/github.com/consensys/bavard/LICENSE new file mode 100644 index 00000000000..f49a4e16e68 --- /dev/null +++ b/vendor/github.com/consensys/bavard/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/vendor/github.com/consensys/bavard/README.md b/vendor/github.com/consensys/bavard/README.md new file mode 100644 index 00000000000..a4ceab6130f --- /dev/null +++ b/vendor/github.com/consensys/bavard/README.md @@ -0,0 +1,9 @@ +# bavard + +Internal package with some code-generation helper (txt/template and asm). + +Used by: + +* [gnark](https://github.com/consensys/gnark) +* [gurvy](https://github.com/consensys/gurvy) +* [goff](https://github.com/consensys/goff) \ No newline at end of file diff --git a/vendor/github.com/consensys/bavard/bavard.go b/vendor/github.com/consensys/bavard/bavard.go new file mode 100644 index 00000000000..c9164dcf426 --- /dev/null +++ b/vendor/github.com/consensys/bavard/bavard.go @@ -0,0 +1,345 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package bavard contains helper functions to generate consistent code from text/template templates. +// it is used by github.com/consensys/gnark && github.com/consensys/gnark-crypto +package bavard + +import ( + "bytes" + "errors" + "fmt" + "io" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + "sync" + "text/template" + + "rsc.io/tmplfunc" +) + +// Bavard root object to configure the code generation from text/template +type Bavard struct { + verbose bool + fmt bool + imports bool + docFile bool + packageName string + license string + generated string + buildTag string + funcs template.FuncMap +} + +// BatchGenerator enables more efficient and clean multiple file generation +type BatchGenerator struct { + defaultOpts []func(*Bavard) error +} + +// NewBatchGenerator returns a new BatchGenerator +func NewBatchGenerator(copyrightHolder string, copyrightYear int, generatedBy string) *BatchGenerator { + return &BatchGenerator{ + defaultOpts: []func(*Bavard) error{ + Apache2(copyrightHolder, copyrightYear), + GeneratedBy(generatedBy), + Format(false), + Import(false), + Verbose(true), + }, + } +} + +// Entry to be used in batch generation of files +type Entry struct { + File string + Templates []string + BuildTag string +} + +// GenerateFromString will concatenate templates and create output file from executing the resulting text/template +// see other package functions to add options (package name, licensing, build tags, ...) +func GenerateFromString(output string, templates []string, data interface{}, options ...func(*Bavard) error) error { + var b Bavard + + var buf bytes.Buffer + + if err := b.config(&buf, output, options...); err != nil { + return err + } + + fnHelpers := helpers() + for k, v := range b.funcs { + fnHelpers[k] = v + } + + tmpl := template.New("").Funcs(fnHelpers) + + if err := tmplfunc.Parse(tmpl, aggregate(templates)); err != nil { + return err + } + + // execute template + if err := tmpl.Execute(&buf, data); err != nil { + return err + } + + return b.create(output, &buf) +} + +// GenerateFromFiles will concatenate templates and create output file from executing the resulting text/template +// see other package functions to add options (package name, licensing, build tags, ...) +func GenerateFromFiles(output string, templateF []string, data interface{}, options ...func(*Bavard) error) error { + var b Bavard + var buf bytes.Buffer + + b.config(&buf, output, options...) + + // parse templates + fnHelpers := helpers() + for k, v := range b.funcs { + fnHelpers[k] = v + } + + if len(templateF) == 0 { + return errors.New("missing templates") + } + tName := path.Base(templateF[0]) + + tmpl := template.New(tName).Funcs(fnHelpers) + + if err := tmplfunc.ParseFiles(tmpl, templateF...); err != nil { + return err + } + + // execute template + if err := tmpl.Execute(&buf, data); err != nil { + return err + } + return b.create(output, &buf) +} + +func (b *Bavard) config(buf *bytes.Buffer, output string, options ...func(*Bavard) error) error { + // default settings + b.imports = false + b.fmt = false + b.verbose = true + b.generated = "bavard" + b.docFile = strings.HasSuffix(output, "doc.go") + + // handle options + for _, option := range options { + if err := option(b); err != nil { + return err + } + } + + if b.buildTag != "" { + if _, err := buf.WriteString("// +build " + b.buildTag + "\n"); err != nil { + return err + } + } + + if b.license != "" { + if _, err := buf.WriteString(b.license + "\n"); err != nil { + return err + } + } + if _, err := buf.WriteString(fmt.Sprintf("// Code generated by %s DO NOT EDIT\n\n", b.generated)); err != nil { + return err + } + + if !b.docFile && b.packageName != "" { + if _, err := buf.WriteString("package " + b.packageName + "\n\n"); err != nil { + return err + } + } + return nil +} + +func (b *Bavard) create(output string, buf *bytes.Buffer) error { + // create output dir if not exist + _ = os.MkdirAll(filepath.Dir(output), os.ModePerm) + + // create output file + file, err := os.Create(output) + if err != nil { + return err + } + if b.verbose { + fmt.Printf("generating %-70s\n", filepath.Clean(output)) + } + if _, err := io.Copy(file, buf); err != nil { + file.Close() + return err + } + + file.Close() + + // format generated code + if b.fmt { + cmd := exec.Command("gofmt", "-s", "-w", output) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + } + + // run goimports on generated code + if b.imports { + cmd := exec.Command("goimports", "-w", output) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + } + + return nil +} + +func aggregate(values []string) string { + var sb strings.Builder + for _, v := range values { + sb.WriteString(v) + } + return sb.String() +} + +// Apache2Header returns a Apache2 header string +func Apache2Header(copyrightHolder string, year int) string { + apache2 := ` + // Copyright %d %s + // + // Licensed under the Apache License, Version 2.0 (the "License"); + // you may not use this file except in compliance with the License. + // You may obtain a copy of the License at + // + // http://www.apache.org/licenses/LICENSE-2.0 + // + // Unless required by applicable law or agreed to in writing, software + // distributed under the License is distributed on an "AS IS" BASIS, + // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + // See the License for the specific language governing permissions and + // limitations under the License. + ` + return fmt.Sprintf(apache2, year, copyrightHolder) +} + +// Apache2 returns a bavard option to be used in Generate writing an apache2 licence header in the generated file +func Apache2(copyrightHolder string, year int) func(*Bavard) error { + return func(b *Bavard) error { + b.license = Apache2Header(copyrightHolder, year) + return nil + } +} + +// GeneratedBy returns a bavard option to be used in Generate writing a standard +// "Code generated by 'label' DO NOT EDIT" +func GeneratedBy(label string) func(*Bavard) error { + return func(b *Bavard) error { + b.generated = label + return nil + } +} + +// BuildTag returns a bavard option to be used in Generate adding build tags string on top of the generated file +func BuildTag(buildTag string) func(*Bavard) error { + return func(b *Bavard) error { + b.buildTag = buildTag + return nil + } +} + +// Package returns a bavard option adding package name and optional package documentation in the generated file +func Package(name string) func(*Bavard) error { + return func(b *Bavard) error { + b.packageName = name + return nil + } +} + +// Verbose returns a bavard option to be used in Generate. If set to true, will print to stdout during code generation +func Verbose(v bool) func(*Bavard) error { + return func(b *Bavard) error { + b.verbose = v + return nil + } +} + +// Format returns a bavard option to be used in Generate. If set to true, will run gofmt on generated file. +// Or simple tab alignment on .s files +func Format(v bool) func(*Bavard) error { + return func(b *Bavard) error { + b.fmt = v + return nil + } +} + +// Import returns a bavard option to be used in Generate. If set to true, will run goimports +func Import(v bool) func(*Bavard) error { + return func(b *Bavard) error { + b.imports = v + return nil + } +} + +// Funcs returns a bavard option to be used in Generate. See text/template FuncMap for more info +func Funcs(funcs template.FuncMap) func(*Bavard) error { + return func(b *Bavard) error { + b.funcs = funcs + return nil + } +} + +// Generate an entry with generator default config +func (b *BatchGenerator) Generate(data interface{}, packageName string, baseTmplDir string, entries ...Entry) error { + return b.GenerateWithOptions(data, packageName, baseTmplDir, make([]func(*Bavard)error,0), entries...) +} + +// GenerateWithOptions allows adding extra configuration (helper functions etc.) to a batch generation +func (b *BatchGenerator) GenerateWithOptions(data interface{}, packageName string, baseTmplDir string, extraOptions []func(*Bavard) error, entries ...Entry) error { + var firstError error + var lock sync.RWMutex + var wg sync.WaitGroup + for i := 0; i < len(entries); i++ { + wg.Add(1) + go func(entry Entry) { + defer wg.Done() + opts := make([]func(*Bavard) error, len(b.defaultOpts) + len(extraOptions)) + copy(opts, b.defaultOpts) + copy(opts[len(b.defaultOpts):], extraOptions) + if entry.BuildTag != "" { + opts = append(opts, BuildTag(entry.BuildTag)) + } + opts = append(opts, Package(packageName)) + for j := 0; j < len(entry.Templates); j++ { + entry.Templates[j] = filepath.Join(baseTmplDir, entry.Templates[j]) + } + if err := GenerateFromFiles(entry.File, entry.Templates, data, opts...); err != nil { + lock.Lock() + if firstError == nil { + firstError = err + } + lock.Unlock() + } + }(entries[i]) + } + wg.Wait() + + return firstError +} \ No newline at end of file diff --git a/vendor/github.com/consensys/bavard/helpers.go b/vendor/github.com/consensys/bavard/helpers.go new file mode 100644 index 00000000000..2e2f91f4fc1 --- /dev/null +++ b/vendor/github.com/consensys/bavard/helpers.go @@ -0,0 +1,525 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bavard + +import ( + "bytes" + "errors" + "fmt" + "math/big" + "math/bits" + "reflect" + "strconv" + "strings" + "sync" + "text/template" +) + +// Template helpers (txt/template) +func helpers() template.FuncMap { + // functions used in template + return template.FuncMap{ + "add": add, + "bits": getBits, + "bytes": intBytes, //TODO: Do this directly + "capitalize": strings.Title, + "dict": dict, + "div": div, + "divides": divides, + "first": first, + "gt": gt, + "interval": interval, + "iterate": iterate, + "select": _select, + "last": last, + "list": makeSlice, + "log": fmt.Println, + "lt": lt, + "mod": mod, + "mul": mul, + "mul2": mul2, + "noFirst": noFirst, + "noLast": noLast, + "notNil": notNil, + "pretty": pretty, + "printList": printList, + "reverse": reverse, + "sub": sub, + "supScr": toSuperscript, + "toInt64": toInt64, + "toLower": strings.ToLower, + "toTitle": strings.Title, + "toUpper": strings.ToUpper, + "words64": bigIntToUint64SliceAsString, + } +} + +func _select(condition bool, ifNot, ifSo interface{}) interface{} { + if condition { + return ifSo + } + return ifNot +} + +func pretty(a interface{}) interface{} { + if res, err := printList(a); err == nil { + return res + } + + if s, ok := a.(big.Int); ok { + return s.String() + } + + return a +} + +func cmp(a, b interface{}, expectedCmp int) (bool, error) { + aI, err := toBigInt(a) + if err != nil { + return false, err + } + var bI big.Int + bI, err = toBigInt(b) + if err != nil { + return false, err + } + return aI.Cmp(&bI) == expectedCmp, nil +} + +func lt(a, b interface{}) (bool, error) { + return cmp(a, b, -1) +} + +func gt(a, b interface{}) (bool, error) { + return cmp(a, b, +1) +} + +func getBitsBig(a big.Int) ([]bool, error) { + l := a.BitLen() + res := make([]bool, l) + for i := 0; i < l; i ++ { + res[i] = a.Bit(i) == 1 + } + return res, nil +} + +func getBits(a interface{}) ([]bool, error) { + + if aBI, ok := a.(big.Int); ok { + return getBitsBig(aBI) + } + + var res []bool + aI, err := toInt64(a) + + if err != nil { + return res, err + } + + for aI != 0 { + res = append(res, aI%2 != 0) + aI /= 2 + } + + return res, nil +} + +func toBigInt(a interface{}) (big.Int, error) { + switch i := a.(type) { + case big.Int: + return i, nil + case *big.Int: + return *i, nil + /*case string: + var res big.Int + res.SetString(i, 0) + return res, nil*/ + default: + n, err := toInt64(i) + return *big.NewInt(n), err + } +} + +func toInt64(a interface{}) (int64, error) { + switch i := a.(type) { + case uint8: + return int64(i), nil + case int8: + return int64(i), nil + case uint16: + return int64(i), nil + case int16: + return int64(i), nil + case uint32: + return int64(i), nil + case int32: + return int64(i), nil + case uint64: + if i>>63 != 0 { + return -1, fmt.Errorf("uint64 value won't fit in int64") + } + return int64(i), nil + case int64: + return i, nil + case int: + return int64(i), nil + case big.Int: + if !i.IsInt64() { + return -1, fmt.Errorf("big.Int value won't fit in int64") + } + return i.Int64(), nil + case *big.Int: + if !i.IsInt64() { + return -1, fmt.Errorf("big.Int value won't fit in int64") + } + return i.Int64(), nil + default: + return 0, fmt.Errorf("cannot convert to int64 from type %T", i) + } +} + +func mod(a, b interface{}) (int64, error) { + + var err error + A, err := toInt64(a) + + if err != nil { + return 0, err + } + + B, err := toInt64(b) + + if err != nil { + return 0, err + } + return A % B, nil +} + +func intBytes(i big.Int) []byte { + return i.Bytes() +} + +func interval(begin, end interface{}) ([]int64, error) { + beginInt, err := toInt64(begin) + if err != nil { + return nil, err + } + endInt, err := toInt64(end) + if err != nil { + return nil, err + } + + l := endInt - beginInt + r := make([]int64, l) + for i := int64(0); i < l; i++ { + r[i] = i + beginInt + } + return r, nil +} + +// Adopted from https://stackoverflow.com/a/50487104/5116581 +func notNil(input interface{}) bool { + isNil := input == nil || (reflect.ValueOf(input).Kind() == reflect.Ptr && reflect.ValueOf(input).IsNil()) + return !isNil +} + +func AssertSlice(input interface{}) (reflect.Value, error) { + s := reflect.ValueOf(input) + if s.Kind() != reflect.Slice { + return s, fmt.Errorf("value %s is not a slice", fmt.Sprint(s)) + } + return s, nil +} + +func first(input interface{}) (interface{}, error) { + s, err := AssertSlice(input) + if err != nil { + return nil, err + } + if s.Len() == 0 { + return nil, fmt.Errorf("empty slice") + } + return s.Index(0).Interface(), nil +} + +func last(input interface{}) (interface{}, error) { + s, err := AssertSlice(input) + if err != nil { + return nil, err + } + if s.Len() == 0 { + return nil, fmt.Errorf("empty slice") + } + return s.Index(s.Len() - 1).Interface(), nil +} + +var StringBuilderPool = sync.Pool{New: func() interface{} { return &strings.Builder{} }} + +func WriteBigIntAsUint64Slice(builder *strings.Builder, input *big.Int) { + words := input.Bits() + + if len(words) == 0 { + builder.WriteString("0") + return + } + + for i := 0; i < len(words); i++ { + w := uint64(words[i]) + + if bits.UintSize == 32 && i < len(words)-1 { + i++ + w = (w << 32) | uint64(words[i]) + } + + builder.WriteString(strconv.FormatUint(w, 10)) + + if i < len(words)-1 { + builder.WriteString(", ") + } + } +} + +func bigIntToUint64SliceAsString(in interface{}) (string, error) { + + var input *big.Int + + switch i := in.(type) { + case big.Int: + input = &i + case *big.Int: + input = i + default: + return "", fmt.Errorf("unsupported type %T", in) + } + + builder := StringBuilderPool.Get().(*strings.Builder) + builder.Reset() + defer StringBuilderPool.Put(builder) + + WriteBigIntAsUint64Slice(builder, input) + + return builder.String(), nil +} + +func printList(input interface{}) (string, error) { + + s, err := AssertSlice(input) + + if err != nil || s.Len() == 0 { + return "", err + } + + builder := StringBuilderPool.Get().(*strings.Builder) + builder.Reset() + defer StringBuilderPool.Put(builder) + + builder.WriteString(fmt.Sprint(pretty(s.Index(0).Interface()))) + + for i := 1; i < s.Len(); i++ { + builder.WriteString(", ") + builder.WriteString(fmt.Sprint(pretty(s.Index(i).Interface()))) + } + + return builder.String(), nil +} + +func iterate(start, end interface{}) (r []int64, err error) { + + startI, err := toInt64(start) + if err != nil { + return nil, err + } + var endI int64 + endI, err = toInt64(end) + + if err != nil { + return nil, err + } + + for i := startI; i < endI; i++ { + r = append(r, i) + } + return +} + +func reverse(input interface{}) interface{} { + + s, err := AssertSlice(input) + if err != nil { + return err + } + l := s.Len() + toReturn := reflect.MakeSlice(s.Type(), l, l) + + l-- + for i := 0; i <= l; i++ { + toReturn.Index(l - i).Set(s.Index(i)) + } + return toReturn.Interface() +} + +func noFirst(input interface{}) interface{} { + s, err := AssertSlice(input) + if s.Len() == 0 { + return input + } + if err != nil { + return err + } + l := s.Len() - 1 + toReturn := reflect.MakeSlice(s.Type(), l, l) + for i := 0; i < l; i++ { + toReturn.Index(i).Set(s.Index(i + 1)) + } + return toReturn.Interface() +} + +func noLast(input interface{}) interface{} { + s, err := AssertSlice(input) + if s.Len() == 0 { + return input + } + if err != nil { + return err + } + l := s.Len() - 1 + toReturn := reflect.MakeSlice(s.Type(), l, l) + for i := 0; i < l; i++ { + toReturn.Index(i).Set(s.Index(i)) + } + return toReturn.Interface() +} + +func add(a, b interface{}) (int64, error) { + aI, err := toInt64(a) + if err != nil { + return 0, err + } + var bI int64 + if bI, err = toInt64(b); err != nil { + return 0, err + } + return aI + bI, nil +} +func mul(a, b interface{}) (int64, error) { + aI, err := toInt64(a) + if err != nil { + return 0, err + } + var bI int64 + if bI, err = toInt64(b); err != nil { + return 0, err + } + return aI * bI, nil +} +func sub(a, b interface{}) (int64, error) { + aI, err := toInt64(a) + if err != nil { + return 0, err + } + var bI int64 + if bI, err = toInt64(b); err != nil { + return 0, err + } + return aI - bI, nil +} +func mul2(a interface{}) (int64, error) { + aI, err := toInt64(a) + if err != nil { + return 0, err + } + + return aI * 2, nil +} +func div(a, b interface{}) (int64, error) { + aI, err := toInt64(a) + if err != nil { + return 0, err + } + var bI int64 + if bI, err = toInt64(b); err != nil { + return 0, err + } + return aI / bI, nil +} + +func makeSlice(values ...interface{}) []interface{} { + return values +} + +func dict(values ...interface{}) (map[string]interface{}, error) { + if len(values)%2 != 0 { + return nil, errors.New("invalid dict call") + } + dict := make(map[string]interface{}, len(values)/2) + for i := 0; i < len(values); i += 2 { + key, ok := values[i].(string) + if !ok { + return nil, errors.New("dict keys must be strings") + } + dict[key] = values[i+1] + } + return dict, nil +} + +// return true if c1 divides c2, that is, c2 % c1 == 0 +func divides(c1, c2 interface{}) (bool, error) { + + //try to convert to int64 + c1Int, err := toInt64(c1) + if err != nil { + return false, err + } + var c2Int int64 + c2Int, err = toInt64(c2) + if err != nil { + return false, err + } + + return c2Int%c1Int == 0, nil +} + +// Imitating supsub +var superscripts = map[rune]rune{ + '0': '⁰', + '1': '¹', + '2': '²', + '3': '³', + '4': '⁴', + '5': '⁵', + '6': '⁶', + '7': '⁷', + '8': '⁸', + '9': '⁹', +} + +// toSuperscript writes a number as a "power" +//TODO: Use https://github.com/lynn9388/supsub ? +//Copying supsub +func toSuperscript(a interface{}) (string, error) { + i, err := toInt64(a) + + if err != nil { + return "", err + } + + s := strconv.FormatInt(i, 10) + var buf bytes.Buffer + for _, r := range s { + sup := superscripts[r] + buf.WriteRune(sup) + } + return buf.String(), nil +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/bls12-377.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/bls12-377.go new file mode 100644 index 00000000000..43fbe1f6c7a --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/bls12-377.go @@ -0,0 +1,156 @@ +// Package bls12377 efficient elliptic curve, pairing and hash to curve implementation for bls12-377. +// +// bls12-377: A Barreto--Lynn--Scott curve with +// +// embedding degree k=12 +// seed x₀=9586122913090633729 +// 𝔽r: r=8444461749428370424248824938781546531375899335154063827935233455917409239041 (x₀⁴-x₀²+1) +// 𝔽p: p=258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 ((x₀-1)² ⋅ r(x₀)/3+x₀) +// (E/𝔽p): Y²=X³+1 +// (Eₜ/𝔽p²): Y² = X³+1/u (D-type twist) +// r ∣ #E(Fp) and r ∣ #Eₜ(𝔽p²) +// +// Extension fields tower: +// +// 𝔽p²[u] = 𝔽p/u²+5 +// 𝔽p⁶[v] = 𝔽p²/v³-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +// +// optimal Ate loop size: +// +// x₀ +// +// Security: estimated 126-bit level following [https://eprint.iacr.org/2019/885.pdf] +// (r is 253 bits and p¹² is 4521 bits) +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +package bls12377 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" +) + +// ID bls377 ID +const ID = ecc.BLS12_377 + +// aCurveCoeff is the a coefficients of the curve Y²=X³+ax+b +var aCurveCoeff fp.Element +var bCurveCoeff fp.Element + +// twist +var twist fptower.E2 + +// bTwistCurveCoeff b coeff of the twist (defined over 𝔽p²) curve +var bTwistCurveCoeff fptower.E2 + +// generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) +var g1Gen G1Jac +var g2Gen G2Jac + +var g1GenAff G1Affine +var g2GenAff G2Affine + +// point at infinity +var g1Infinity G1Jac +var g2Infinity G2Jac + +// optimal Ate loop counter +var loopCounter [64]int8 + +// Parameters useful for the GLV scalar multiplication. The third roots define the +// endomorphisms ϕ₁ and ϕ₂ for and . lambda is such that lies above +// in the ring Z[ϕ]. More concretely it's the associated eigenvalue +// of ϕ₁ (resp ϕ₂) restricted to (resp ) +// see https://www.cosic.esat.kuleuven.be/nessie/reports/phase2/GLV.pdf +var thirdRootOneG1 fp.Element +var thirdRootOneG2 fp.Element +var lambdaGLV big.Int + +// glvBasis stores R-linearly independent vectors (a,b), (c,d) +// in ker((u,v) → u+vλ[r]), and their determinant +var glvBasis ecc.Lattice + +// ψ o π o ψ⁻¹, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² +var endo struct { + u fptower.E2 + v fptower.E2 +} + +// seed x₀ of the curve +var xGen big.Int + +// expose the tower -- github.com/consensys/gnark uses it in a gnark circuit + +// 𝔽p² +type E2 = fptower.E2 + +// 𝔽p⁶ +type E6 = fptower.E6 + +// 𝔽p¹² +type E12 = fptower.E12 + +func init() { + aCurveCoeff.SetUint64(0) + bCurveCoeff.SetUint64(1) + // D-twist + twist.A1.SetUint64(1) + bTwistCurveCoeff.Inverse(&twist) + + g1Gen.X.SetString("81937999373150964239938255573465948239988671502647976594219695644855304257327692006745978603320413799295628339695") + g1Gen.Y.SetString("241266749859715473739788878240585681733927191168601896383759122102112907357779751001206799952863815012735208165030") + g1Gen.Z.SetOne() + + g2Gen.X.SetString("233578398248691099356572568220835526895379068987715365179118596935057653620464273615301663571204657964920925606294", + "140913150380207355837477652521042157274541796891053068589147167627541651775299824604154852141315666357241556069118") + g2Gen.Y.SetString("63160294768292073209381361943935198908131692476676907196754037919244929611450776219210369229519898517858833747423", + "149157405641012693445398062341192467754805999074082136895788947234480009303640899064710353187729182149407503257491") + g2Gen.Z.SetString("1", + "0") + + g1GenAff.FromJacobian(&g1Gen) + g2GenAff.FromJacobian(&g2Gen) + + // (X,Y,Z) = (1,1,0) + g1Infinity.X.SetOne() + g1Infinity.Y.SetOne() + g2Infinity.X.SetOne() + g2Infinity.Y.SetOne() + + thirdRootOneG1.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945") + thirdRootOneG2.Square(&thirdRootOneG1) + lambdaGLV.SetString("91893752504881257701523279626832445440", 10) //(x₀²-1) + _r := fr.Modulus() + ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + + endo.u.A0.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946") + endo.v.A0.SetString("216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499") + + // binary decomposition of x₀ little endian + loopCounter = [64]int8{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1} + + // x₀ + xGen.SetString("9586122913090633729", 10) + +} + +// Generators return the generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) +func Generators() (g1Jac G1Jac, g2Jac G2Jac, g1Aff G1Affine, g2Aff G2Affine) { + g1Aff = g1GenAff + g2Aff = g2GenAff + g1Jac = g1Gen + g2Jac = g2Gen + return +} + +// CurveCoefficients returns the a, b coefficients of the curve equation. +func CurveCoefficients() (a, b fp.Element) { + return aCurveCoeff, bCurveCoeff +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/arith.go new file mode 100644 index 00000000000..6f281563b3d --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/arith.go @@ -0,0 +1,73 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "math/bits" +) + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} +func max(a int, b int) int { + if a > b { + return a + } + return b +} + +func min(a int, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm.go similarity index 80% rename from vendor/github.com/consensys/gnark-crypto/ecc/bn254/doc.go rename to vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm.go index df3457ba2ae..0481989ec6a 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/doc.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm.go @@ -1,3 +1,6 @@ +//go:build !noadx +// +build !noadx + // Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,5 +17,11 @@ // Code generated by consensys/gnark-crypto DO NOT EDIT -// Package bn254 efficient elliptic curve and pairing implementation for bn254. -package bn254 +package fp + +import "golang.org/x/sys/cpu" + +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm_noadx.go new file mode 100644 index 00000000000..92f8cc0f424 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/asm_noadx.go @@ -0,0 +1,28 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var ( + supportAdx = false + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/doc.go new file mode 100644 index 00000000000..c4d87f7b017 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/doc.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package fp contains field arithmetic operations for modulus = 0x1ae3a4...000001. +// +// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x for the modular multiplication on amd64, see also https://hackmd.io/@gnark/modular_multiplication) +// +// The modulus is hardcoded in all the operations. +// +// Field elements are represented as an array, and assumed to be in Montgomery form in all methods: +// +// type Element [6]uint64 +// +// # Usage +// +// Example API signature: +// +// // Mul z = x * y (mod q) +// func (z *Element) Mul(x, y *Element) *Element +// +// and can be used like so: +// +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus q = +// +// q[base10] = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +// q[base16] = 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +package fp diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go new file mode 100644 index 00000000000..81a730fbd4c --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go @@ -0,0 +1,1848 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "crypto/rand" + "encoding/binary" + "errors" + "io" + "math/big" + "math/bits" + "reflect" + "strconv" + "strings" + + "github.com/bits-and-blooms/bitset" + "github.com/consensys/gnark-crypto/field/hash" + "github.com/consensys/gnark-crypto/field/pool" +) + +// Element represents a field element stored on 6 words (uint64) +// +// Element are assumed to be in Montgomery form in all methods. +// +// Modulus q = +// +// q[base10] = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +// q[base16] = 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +type Element [6]uint64 + +const ( + Limbs = 6 // number of 64 bits words needed to represent a Element + Bits = 377 // number of bits needed to represent a Element + Bytes = 48 // number of bytes needed to represent a Element +) + +// Field modulus q +const ( + q0 uint64 = 9586122913090633729 + q1 uint64 = 1660523435060625408 + q2 uint64 = 2230234197602682880 + q3 uint64 = 1883307231910630287 + q4 uint64 = 14284016967150029115 + q5 uint64 = 121098312706494698 +) + +var qElement = Element{ + q0, + q1, + q2, + q3, + q4, + q5, +} + +var _modulus big.Int // q stored as big.Int + +// Modulus returns q as a big.Int +// +// q[base10] = 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 +// q[base16] = 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 +func Modulus() *big.Int { + return new(big.Int).Set(&_modulus) +} + +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 9586122913090633727 + +func init() { + _modulus.SetString("1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001", 16) +} + +// NewElement returns a new Element from a uint64 value +// +// it is equivalent to +// +// var v Element +// v.SetUint64(...) +func NewElement(v uint64) Element { + z := Element{v} + z.Mul(&z, &rSquare) + return z +} + +// SetUint64 sets z to v and returns z +func (z *Element) SetUint64(v uint64) *Element { + // sets z LSB to v (non-Montgomery form) and convert z to Montgomery form + *z = Element{v} + return z.Mul(z, &rSquare) // z.toMont() +} + +// SetInt64 sets z to v and returns z +func (z *Element) SetInt64(v int64) *Element { + + // absolute value of v + m := v >> 63 + z.SetUint64(uint64((v ^ m) - m)) + + if m != 0 { + // v is negative + z.Neg(z) + } + + return z +} + +// Set z = x and returns z +func (z *Element) Set(x *Element) *Element { + z[0] = x[0] + z[1] = x[1] + z[2] = x[2] + z[3] = x[3] + z[4] = x[4] + z[5] = x[5] + return z +} + +// SetInterface converts provided interface into Element +// returns an error if provided type is not supported +// supported types: +// +// Element +// *Element +// uint64 +// int +// string (see SetString for valid formats) +// *big.Int +// big.Int +// []byte +func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + if i1 == nil { + return nil, errors.New("can't set fp.Element with ") + } + + switch c1 := i1.(type) { + case Element: + return z.Set(&c1), nil + case *Element: + if c1 == nil { + return nil, errors.New("can't set fp.Element with ") + } + return z.Set(c1), nil + case uint8: + return z.SetUint64(uint64(c1)), nil + case uint16: + return z.SetUint64(uint64(c1)), nil + case uint32: + return z.SetUint64(uint64(c1)), nil + case uint: + return z.SetUint64(uint64(c1)), nil + case uint64: + return z.SetUint64(c1), nil + case int8: + return z.SetInt64(int64(c1)), nil + case int16: + return z.SetInt64(int64(c1)), nil + case int32: + return z.SetInt64(int64(c1)), nil + case int64: + return z.SetInt64(c1), nil + case int: + return z.SetInt64(int64(c1)), nil + case string: + return z.SetString(c1) + case *big.Int: + if c1 == nil { + return nil, errors.New("can't set fp.Element with ") + } + return z.SetBigInt(c1), nil + case big.Int: + return z.SetBigInt(&c1), nil + case []byte: + return z.SetBytes(c1), nil + default: + return nil, errors.New("can't set fp.Element from type " + reflect.TypeOf(i1).String()) + } +} + +// SetZero z = 0 +func (z *Element) SetZero() *Element { + z[0] = 0 + z[1] = 0 + z[2] = 0 + z[3] = 0 + z[4] = 0 + z[5] = 0 + return z +} + +// SetOne z = 1 (in Montgomery form) +func (z *Element) SetOne() *Element { + z[0] = 202099033278250856 + z[1] = 5854854902718660529 + z[2] = 11492539364873682930 + z[3] = 8885205928937022213 + z[4] = 5545221690922665192 + z[5] = 39800542322357402 + return z +} + +// Div z = x*y⁻¹ (mod q) +func (z *Element) Div(x, y *Element) *Element { + var yInv Element + yInv.Inverse(y) + z.Mul(x, &yInv) + return z +} + +// Equal returns z == x; constant-time +func (z *Element) Equal(x *Element) bool { + return z.NotEqual(x) == 0 +} + +// NotEqual returns 0 if and only if z == x; constant-time +func (z *Element) NotEqual(x *Element) uint64 { + return (z[5] ^ x[5]) | (z[4] ^ x[4]) | (z[3] ^ x[3]) | (z[2] ^ x[2]) | (z[1] ^ x[1]) | (z[0] ^ x[0]) +} + +// IsZero returns z == 0 +func (z *Element) IsZero() bool { + return (z[5] | z[4] | z[3] | z[2] | z[1] | z[0]) == 0 +} + +// IsOne returns z == 1 +func (z *Element) IsOne() bool { + return ((z[5] ^ 39800542322357402) | (z[4] ^ 5545221690922665192) | (z[3] ^ 8885205928937022213) | (z[2] ^ 11492539364873682930) | (z[1] ^ 5854854902718660529) | (z[0] ^ 202099033278250856)) == 0 +} + +// IsUint64 reports whether z can be represented as an uint64. +func (z *Element) IsUint64() bool { + zz := *z + zz.fromMont() + return zz.FitsOnOneWord() +} + +// Uint64 returns the uint64 representation of x. If x cannot be represented in a uint64, the result is undefined. +func (z *Element) Uint64() uint64 { + return z.Bits()[0] +} + +// FitsOnOneWord reports whether z words (except the least significant word) are 0 +// +// It is the responsibility of the caller to convert from Montgomery to Regular form if needed. +func (z *Element) FitsOnOneWord() bool { + return (z[5] | z[4] | z[3] | z[2] | z[1]) == 0 +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *Element) Cmp(x *Element) int { + _z := z.Bits() + _x := x.Bits() + if _z[5] > _x[5] { + return 1 + } else if _z[5] < _x[5] { + return -1 + } + if _z[4] > _x[4] { + return 1 + } else if _z[4] < _x[4] { + return -1 + } + if _z[3] > _x[3] { + return 1 + } else if _z[3] < _x[3] { + return -1 + } + if _z[2] > _x[2] { + return 1 + } else if _z[2] < _x[2] { + return -1 + } + if _z[1] > _x[1] { + return 1 + } else if _z[1] < _x[1] { + return -1 + } + if _z[0] > _x[0] { + return 1 + } else if _z[0] < _x[0] { + return -1 + } + return 0 +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *Element) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + // we check if the element is larger than (q-1) / 2 + // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 + + _z := z.Bits() + + var b uint64 + _, b = bits.Sub64(_z[0], 4793061456545316865, 0) + _, b = bits.Sub64(_z[1], 830261717530312704, b) + _, b = bits.Sub64(_z[2], 10338489135656117248, b) + _, b = bits.Sub64(_z[3], 10165025652810090951, b) + _, b = bits.Sub64(_z[4], 7142008483575014557, b) + _, b = bits.Sub64(_z[5], 60549156353247349, b) + + return b == 0 +} + +// SetRandom sets z to a uniform random value in [0, q). +// +// This might error only if reading from crypto/rand.Reader errors, +// in which case, value of z is undefined. +func (z *Element) SetRandom() (*Element, error) { + // this code is generated for all modulus + // and derived from go/src/crypto/rand/util.go + + // l is number of limbs * 8; the number of bytes needed to reconstruct 6 uint64 + const l = 48 + + // bitLen is the maximum bit length needed to encode a value < q. + const bitLen = 377 + + // k is the maximum byte length needed to encode a value < q. + const k = (bitLen + 7) / 8 + + // b is the number of bits in the most significant byte of q-1. + b := uint(bitLen % 8) + if b == 0 { + b = 8 + } + + var bytes [l]byte + + for { + // note that bytes[k:l] is always 0 + if _, err := io.ReadFull(rand.Reader, bytes[:k]); err != nil { + return nil, err + } + + // Clear unused bits in in the most significant byte to increase probability + // that the candidate is < q. + bytes[k-1] &= uint8(int(1<> 1 + z[0] = z[0]>>1 | z[1]<<63 + z[1] = z[1]>>1 | z[2]<<63 + z[2] = z[2]>>1 | z[3]<<63 + z[3] = z[3]>>1 | z[4]<<63 + z[4] = z[4]>>1 | z[5]<<63 + z[5] >>= 1 + +} + +// fromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func (z *Element) fromMont() *Element { + fromMont(z) + return z +} + +// Add z = x + y (mod q) +func (z *Element) Add(x, y *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], carry = bits.Add64(x[3], y[3], carry) + z[4], carry = bits.Add64(x[4], y[4], carry) + z[5], _ = bits.Add64(x[5], y[5], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} + +// Double z = x + x (mod q), aka Lsh 1 +func (z *Element) Double(x *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], carry = bits.Add64(x[3], x[3], carry) + z[4], carry = bits.Add64(x[4], x[4], carry) + z[5], _ = bits.Add64(x[5], x[5], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} + +// Sub z = x - y (mod q) +func (z *Element) Sub(x, y *Element) *Element { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + z[4], b = bits.Sub64(x[4], y[4], b) + z[5], b = bits.Sub64(x[5], y[5], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], q0, 0) + z[1], c = bits.Add64(z[1], q1, c) + z[2], c = bits.Add64(z[2], q2, c) + z[3], c = bits.Add64(z[3], q3, c) + z[4], c = bits.Add64(z[4], q4, c) + z[5], _ = bits.Add64(z[5], q5, c) + } + return z +} + +// Neg z = q - x +func (z *Element) Neg(x *Element) *Element { + if x.IsZero() { + z.SetZero() + return z + } + var borrow uint64 + z[0], borrow = bits.Sub64(q0, x[0], 0) + z[1], borrow = bits.Sub64(q1, x[1], borrow) + z[2], borrow = bits.Sub64(q2, x[2], borrow) + z[3], borrow = bits.Sub64(q3, x[3], borrow) + z[4], borrow = bits.Sub64(q4, x[4], borrow) + z[5], _ = bits.Sub64(q5, x[5], borrow) + return z +} + +// Select is a constant-time conditional move. +// If c=0, z = x0. Else z = x1 +func (z *Element) Select(c int, x0 *Element, x1 *Element) *Element { + cC := uint64((int64(c) | -int64(c)) >> 63) // "canonicized" into: 0 if c=0, -1 otherwise + z[0] = x0[0] ^ cC&(x0[0]^x1[0]) + z[1] = x0[1] ^ cC&(x0[1]^x1[1]) + z[2] = x0[2] ^ cC&(x0[2]^x1[2]) + z[3] = x0[3] ^ cC&(x0[3]^x1[3]) + z[4] = x0[4] ^ cC&(x0[4]^x1[4]) + z[5] = x0[5] ^ cC&(x0[5]^x1[5]) + return z +} + +// _mulGeneric is unoptimized textbook CIOS +// it is a fallback solution on x86 when ADX instruction set is not available +// and is used for testing purposes. +func _mulGeneric(z, x, y *Element) { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + + var t [7]uint64 + var D uint64 + var m, C uint64 + // ----------------------------------- + // First loop + + C, t[0] = bits.Mul64(y[0], x[0]) + C, t[1] = madd1(y[0], x[1], C) + C, t[2] = madd1(y[0], x[2], C) + C, t[3] = madd1(y[0], x[3], C) + C, t[4] = madd1(y[0], x[4], C) + C, t[5] = madd1(y[0], x[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[1], x[0], t[0]) + C, t[1] = madd2(y[1], x[1], t[1], C) + C, t[2] = madd2(y[1], x[2], t[2], C) + C, t[3] = madd2(y[1], x[3], t[3], C) + C, t[4] = madd2(y[1], x[4], t[4], C) + C, t[5] = madd2(y[1], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[2], x[0], t[0]) + C, t[1] = madd2(y[2], x[1], t[1], C) + C, t[2] = madd2(y[2], x[2], t[2], C) + C, t[3] = madd2(y[2], x[3], t[3], C) + C, t[4] = madd2(y[2], x[4], t[4], C) + C, t[5] = madd2(y[2], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[3], x[0], t[0]) + C, t[1] = madd2(y[3], x[1], t[1], C) + C, t[2] = madd2(y[3], x[2], t[2], C) + C, t[3] = madd2(y[3], x[3], t[3], C) + C, t[4] = madd2(y[3], x[4], t[4], C) + C, t[5] = madd2(y[3], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[4], x[0], t[0]) + C, t[1] = madd2(y[4], x[1], t[1], C) + C, t[2] = madd2(y[4], x[2], t[2], C) + C, t[3] = madd2(y[4], x[3], t[3], C) + C, t[4] = madd2(y[4], x[4], t[4], C) + C, t[5] = madd2(y[4], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[5], x[0], t[0]) + C, t[1] = madd2(y[5], x[1], t[1], C) + C, t[2] = madd2(y[5], x[2], t[2], C) + C, t[3] = madd2(y[5], x[3], t[3], C) + C, t[4] = madd2(y[5], x[4], t[4], C) + C, t[5] = madd2(y[5], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + + if t[6] != 0 { + // we need to reduce, we have a result on 7 words + var b uint64 + z[0], b = bits.Sub64(t[0], q0, 0) + z[1], b = bits.Sub64(t[1], q1, b) + z[2], b = bits.Sub64(t[2], q2, b) + z[3], b = bits.Sub64(t[3], q3, b) + z[4], b = bits.Sub64(t[4], q4, b) + z[5], _ = bits.Sub64(t[5], q5, b) + return + } + + // copy t into z + z[0] = t[0] + z[1] = t[1] + z[2] = t[2] + z[3] = t[3] + z[4] = t[4] + z[5] = t[5] + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } +} + +func _fromMontGeneric(z *Element) { + // the following lines implement z = z * 1 + // with a modified CIOS montgomery multiplication + // see Mul for algorithm documentation + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } +} + +func _reduceGeneric(z *Element) { + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } +} + +// BatchInvert returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +func BatchInvert(a []Element) []Element { + res := make([]Element, len(a)) + if len(a) == 0 { + return res + } + + zeroes := bitset.New(uint(len(a))) + accumulator := One() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes.Set(uint(i)) + continue + } + res[i] = accumulator + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes.Test(uint(i)) { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func _butterflyGeneric(a, b *Element) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// BitLen returns the minimum number of bits needed to represent z +// returns 0 if z == 0 +func (z *Element) BitLen() int { + if z[5] != 0 { + return 320 + bits.Len64(z[5]) + } + if z[4] != 0 { + return 256 + bits.Len64(z[4]) + } + if z[3] != 0 { + return 192 + bits.Len64(z[3]) + } + if z[2] != 0 { + return 128 + bits.Len64(z[2]) + } + if z[1] != 0 { + return 64 + bits.Len64(z[1]) + } + return bits.Len64(z[0]) +} + +// Hash msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func Hash(msg, dst []byte, count int) ([]Element, error) { + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + const Bytes = 1 + (Bits-1)/8 + const L = 16 + Bytes + + lenInBytes := count * L + pseudoRandomBytes, err := hash.ExpandMsgXmd(msg, dst, lenInBytes) + if err != nil { + return nil, err + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + res := make([]Element, count) + for i := 0; i < count; i++ { + vv.SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + res[i].SetBigInt(vv) + } + + // release object into pool + pool.BigInt.Put(vv) + + return res, nil +} + +// Exp z = xᵏ (mod q) +func (z *Element) Exp(x Element, k *big.Int) *Element { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q) == (x⁻¹)ᵏ (mod q) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = pool.BigInt.Get() + defer pool.BigInt.Put(e) + e.Neg(k) + } + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// rSquare where r is the Montgommery constant +// see section 2.3.2 of Tolga Acar's thesis +// https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf +var rSquare = Element{ + 13224372171368877346, + 227991066186625457, + 2496666625421784173, + 13825906835078366124, + 9475172226622360569, + 30958721782860680, +} + +// toMont converts z to Montgomery form +// sets and returns z = z * r² +func (z *Element) toMont() *Element { + return z.Mul(z, &rSquare) +} + +// String returns the decimal representation of z as generated by +// z.Text(10). +func (z *Element) String() string { + return z.Text(10) +} + +// toBigInt returns z as a big.Int in Montgomery form +func (z *Element) toBigInt(res *big.Int) *big.Int { + var b [Bytes]byte + binary.BigEndian.PutUint64(b[40:48], z[0]) + binary.BigEndian.PutUint64(b[32:40], z[1]) + binary.BigEndian.PutUint64(b[24:32], z[2]) + binary.BigEndian.PutUint64(b[16:24], z[3]) + binary.BigEndian.PutUint64(b[8:16], z[4]) + binary.BigEndian.PutUint64(b[0:8], z[5]) + + return res.SetBytes(b[:]) +} + +// Text returns the string representation of z in the given base. +// Base must be between 2 and 36, inclusive. The result uses the +// lower-case letters 'a' to 'z' for digit values 10 to 35. +// No prefix (such as "0x") is added to the string. If z is a nil +// pointer it returns "". +// If base == 10 and -z fits in a uint16 prefix "-" is added to the string. +func (z *Element) Text(base int) string { + if base < 2 || base > 36 { + panic("invalid base") + } + if z == nil { + return "" + } + + const maxUint16 = 65535 + if base == 10 { + var zzNeg Element + zzNeg.Neg(z) + zzNeg.fromMont() + if zzNeg.FitsOnOneWord() && zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { + return "-" + strconv.FormatUint(zzNeg[0], base) + } + } + zz := *z + zz.fromMont() + if zz.FitsOnOneWord() { + return strconv.FormatUint(zz[0], base) + } + vv := pool.BigInt.Get() + r := zz.toBigInt(vv).Text(base) + pool.BigInt.Put(vv) + return r +} + +// BigInt sets and return z as a *big.Int +func (z *Element) BigInt(res *big.Int) *big.Int { + _z := *z + _z.fromMont() + return _z.toBigInt(res) +} + +// ToBigIntRegular returns z as a big.Int in regular form +// +// Deprecated: use BigInt(*big.Int) instead +func (z Element) ToBigIntRegular(res *big.Int) *big.Int { + z.fromMont() + return z.toBigInt(res) +} + +// Bits provides access to z by returning its value as a little-endian [6]uint64 array. +// Bits is intended to support implementation of missing low-level Element +// functionality outside this package; it should be avoided otherwise. +func (z *Element) Bits() [6]uint64 { + _z := *z + fromMont(&_z) + return _z +} + +// Bytes returns the value of z as a big-endian byte array +func (z *Element) Bytes() (res [Bytes]byte) { + BigEndian.PutElement(&res, *z) + return +} + +// Marshal returns the value of z as a big-endian byte slice +func (z *Element) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// Unmarshal is an alias for SetBytes, it sets z to the value of e. +func (z *Element) Unmarshal(e []byte) { + z.SetBytes(e) +} + +// SetBytes interprets e as the bytes of a big-endian unsigned integer, +// sets z to that value, and returns z. +func (z *Element) SetBytes(e []byte) *Element { + if len(e) == Bytes { + // fast path + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err == nil { + *z = v + return z + } + } + + // slow path. + // get a big int from our pool + vv := pool.BigInt.Get() + vv.SetBytes(e) + + // set big int + z.SetBigInt(vv) + + // put temporary object back in pool + pool.BigInt.Put(vv) + + return z +} + +// SetBytesCanonical interprets e as the bytes of a big-endian 48-byte integer. +// If e is not a 48-byte slice or encodes a value higher than q, +// SetBytesCanonical returns an error. +func (z *Element) SetBytesCanonical(e []byte) error { + if len(e) != Bytes { + return errors.New("invalid fp.Element encoding") + } + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err != nil { + return err + } + *z = v + return nil +} + +// SetBigInt sets z to v and returns z +func (z *Element) SetBigInt(v *big.Int) *Element { + z.SetZero() + + var zero big.Int + + // fast path + c := v.Cmp(&_modulus) + if c == 0 { + // v == 0 + return z + } else if c != 1 && v.Cmp(&zero) != -1 { + // 0 < v < q + return z.setBigInt(v) + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + // copy input + modular reduction + vv.Mod(v, &_modulus) + + // set big int byte value + z.setBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return z +} + +// setBigInt assumes 0 ⩽ v < q +func (z *Element) setBigInt(v *big.Int) *Element { + vBits := v.Bits() + + if bits.UintSize == 64 { + for i := 0; i < len(vBits); i++ { + z[i] = uint64(vBits[i]) + } + } else { + for i := 0; i < len(vBits); i++ { + if i%2 == 0 { + z[i/2] = uint64(vBits[i]) + } else { + z[i/2] |= uint64(vBits[i]) << 32 + } + } + } + + return z.toMont() +} + +// SetString creates a big.Int with number and calls SetBigInt on z +// +// The number prefix determines the actual base: A prefix of +// ”0b” or ”0B” selects base 2, ”0”, ”0o” or ”0O” selects base 8, +// and ”0x” or ”0X” selects base 16. Otherwise, the selected base is 10 +// and no prefix is accepted. +// +// For base 16, lower and upper case letters are considered the same: +// The letters 'a' to 'f' and 'A' to 'F' represent digit values 10 to 15. +// +// An underscore character ”_” may appear between a base +// prefix and an adjacent digit, and between successive digits; such +// underscores do not change the value of the number. +// Incorrect placement of underscores is reported as a panic if there +// are no other errors. +// +// If the number is invalid this method leaves z unchanged and returns nil, error. +func (z *Element) SetString(number string) (*Element, error) { + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(number, 0); !ok { + return nil, errors.New("Element.SetString failed -> can't parse number into a big.Int " + number) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + + return z, nil +} + +// MarshalJSON returns json encoding of z (z.Text(10)) +// If z == nil, returns null +func (z *Element) MarshalJSON() ([]byte, error) { + if z == nil { + return []byte("null"), nil + } + const maxSafeBound = 15 // we encode it as number if it's small + s := z.Text(10) + if len(s) <= maxSafeBound { + return []byte(s), nil + } + var sbb strings.Builder + sbb.WriteByte('"') + sbb.WriteString(s) + sbb.WriteByte('"') + return []byte(sbb.String()), nil +} + +// UnmarshalJSON accepts numbers and strings as input +// See Element.SetString for valid prefixes (0x, 0b, ...) +func (z *Element) UnmarshalJSON(data []byte) error { + s := string(data) + if len(s) > Bits*3 { + return errors.New("value too large (max = Element.Bits * 3)") + } + + // we accept numbers and strings, remove leading and trailing quotes if any + if len(s) > 0 && s[0] == '"' { + s = s[1:] + } + if len(s) > 0 && s[len(s)-1] == '"' { + s = s[:len(s)-1] + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(s, 0); !ok { + return errors.New("can't parse into a big.Int: " + s) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return nil +} + +// A ByteOrder specifies how to convert byte slices into a Element +type ByteOrder interface { + Element(*[Bytes]byte) (Element, error) + PutElement(*[Bytes]byte, Element) + String() string +} + +// BigEndian is the big-endian implementation of ByteOrder and AppendByteOrder. +var BigEndian bigEndian + +type bigEndian struct{} + +// Element interpret b is a big-endian 48-byte slice. +// If b encodes a value higher than q, Element returns error. +func (bigEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.BigEndian.Uint64((*b)[40:48]) + z[1] = binary.BigEndian.Uint64((*b)[32:40]) + z[2] = binary.BigEndian.Uint64((*b)[24:32]) + z[3] = binary.BigEndian.Uint64((*b)[16:24]) + z[4] = binary.BigEndian.Uint64((*b)[8:16]) + z[5] = binary.BigEndian.Uint64((*b)[0:8]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fp.Element encoding") + } + + z.toMont() + return z, nil +} + +func (bigEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.BigEndian.PutUint64((*b)[40:48], e[0]) + binary.BigEndian.PutUint64((*b)[32:40], e[1]) + binary.BigEndian.PutUint64((*b)[24:32], e[2]) + binary.BigEndian.PutUint64((*b)[16:24], e[3]) + binary.BigEndian.PutUint64((*b)[8:16], e[4]) + binary.BigEndian.PutUint64((*b)[0:8], e[5]) +} + +func (bigEndian) String() string { return "BigEndian" } + +// LittleEndian is the little-endian implementation of ByteOrder and AppendByteOrder. +var LittleEndian littleEndian + +type littleEndian struct{} + +func (littleEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.LittleEndian.Uint64((*b)[0:8]) + z[1] = binary.LittleEndian.Uint64((*b)[8:16]) + z[2] = binary.LittleEndian.Uint64((*b)[16:24]) + z[3] = binary.LittleEndian.Uint64((*b)[24:32]) + z[4] = binary.LittleEndian.Uint64((*b)[32:40]) + z[5] = binary.LittleEndian.Uint64((*b)[40:48]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fp.Element encoding") + } + + z.toMont() + return z, nil +} + +func (littleEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.LittleEndian.PutUint64((*b)[0:8], e[0]) + binary.LittleEndian.PutUint64((*b)[8:16], e[1]) + binary.LittleEndian.PutUint64((*b)[16:24], e[2]) + binary.LittleEndian.PutUint64((*b)[24:32], e[3]) + binary.LittleEndian.PutUint64((*b)[32:40], e[4]) + binary.LittleEndian.PutUint64((*b)[40:48], e[5]) +} + +func (littleEndian) String() string { return "LittleEndian" } + +// Legendre returns the Legendre symbol of z (either +1, -1, or 0.) +func (z *Element) Legendre() int { + var l Element + // z^((q-1)/2) + l.expByLegendreExp(*z) + + if l.IsZero() { + return 0 + } + + // if l == 1 + if l.IsOne() { + return 1 + } + return -1 +} + +// Sqrt z = √x (mod q) +// if the square root doesn't exist (x is not a square mod q) +// Sqrt leaves z unchanged and returns nil +func (z *Element) Sqrt(x *Element) *Element { + // q ≡ 1 (mod 4) + // see modSqrtTonelliShanks in math/big/int.go + // using https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + + var y, b, t, w Element + // w = x^((s-1)/2)) + w.expBySqrtExp(*x) + + // y = x^((s+1)/2)) = w * x + y.Mul(x, &w) + + // b = xˢ = w * w * x = y * x + b.Mul(&w, &y) + + // g = nonResidue ^ s + var g = Element{ + 7563926049028936178, + 2688164645460651601, + 12112688591437172399, + 3177973240564633687, + 14764383749841851163, + 52487407124055189, + } + r := uint64(46) + + // compute legendre symbol + // t = x^((q-1)/2) = r-1 squaring of xˢ + t = b + for i := uint64(0); i < r-1; i++ { + t.Square(&t) + } + if t.IsZero() { + return z.SetZero() + } + if !t.IsOne() { + // t != 1, we don't have a square root + return nil + } + for { + var m uint64 + t = b + + // for t != 1 + for !t.IsOne() { + t.Square(&t) + m++ + } + + if m == 0 { + return z.Set(&y) + } + // t = g^(2^(r-m-1)) (mod q) + ge := int(r - m - 1) + t = g + for ge > 0 { + t.Square(&t) + ge-- + } + + g.Square(&t) + y.Mul(&y, &t) + b.Mul(&b, &g) + r = m + } +} + +const ( + k = 32 // word size / 2 + signBitSelector = uint64(1) << 63 + approxLowBitsN = k - 1 + approxHighBitsN = k + 1 +) + +const ( + inversionCorrectionFactorWord0 = 16386826051656692015 + inversionCorrectionFactorWord1 = 8373462824848618879 + inversionCorrectionFactorWord2 = 7553521018781888459 + inversionCorrectionFactorWord3 = 595240760696852504 + inversionCorrectionFactorWord4 = 16794241053652767540 + inversionCorrectionFactorWord5 = 43911691917702151 + invIterationsN = 26 +) + +// Inverse z = x⁻¹ (mod q) +// +// if x == 0, sets and returns z = x +func (z *Element) Inverse(x *Element) *Element { + // Implements "Optimized Binary GCD for Modular Inversion" + // https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf + + a := *x + b := Element{ + q0, + q1, + q2, + q3, + q4, + q5, + } // b := q + + u := Element{1} + + // Update factors: we get [u; v] ← [f₀ g₀; f₁ g₁] [u; v] + // cᵢ = fᵢ + 2³¹ - 1 + 2³² * (gᵢ + 2³¹ - 1) + var c0, c1 int64 + + // Saved update factors to reduce the number of field multiplications + var pf0, pf1, pg0, pg1 int64 + + var i uint + + var v, s Element + + // Since u,v are updated every other iteration, we must make sure we terminate after evenly many iterations + // This also lets us get away with half as many updates to u,v + // To make this constant-time-ish, replace the condition with i < invIterationsN + for i = 0; i&1 == 1 || !a.IsZero(); i++ { + n := max(a.BitLen(), b.BitLen()) + aApprox, bApprox := approximate(&a, n), approximate(&b, n) + + // f₀, g₀, f₁, g₁ = 1, 0, 0, 1 + c0, c1 = updateFactorIdentityMatrixRow0, updateFactorIdentityMatrixRow1 + + for j := 0; j < approxLowBitsN; j++ { + + // -2ʲ < f₀, f₁ ≤ 2ʲ + // |f₀| + |f₁| < 2ʲ⁺¹ + + if aApprox&1 == 0 { + aApprox /= 2 + } else { + s, borrow := bits.Sub64(aApprox, bApprox, 0) + if borrow == 1 { + s = bApprox - aApprox + bApprox = aApprox + c0, c1 = c1, c0 + // invariants unchanged + } + + aApprox = s / 2 + c0 = c0 - c1 + + // Now |f₀| < 2ʲ⁺¹ ≤ 2ʲ⁺¹ (only the weaker inequality is needed, strictly speaking) + // Started with f₀ > -2ʲ and f₁ ≤ 2ʲ, so f₀ - f₁ > -2ʲ⁺¹ + // Invariants unchanged for f₁ + } + + c1 *= 2 + // -2ʲ⁺¹ < f₁ ≤ 2ʲ⁺¹ + // So now |f₀| + |f₁| < 2ʲ⁺² + } + + s = a + + var g0 int64 + // from this point on c0 aliases for f0 + c0, g0 = updateFactorsDecompose(c0) + aHi := a.linearCombNonModular(&s, c0, &b, g0) + if aHi&signBitSelector != 0 { + // if aHi < 0 + c0, g0 = -c0, -g0 + aHi = negL(&a, aHi) + } + // right-shift a by k-1 bits + a[0] = (a[0] >> approxLowBitsN) | ((a[1]) << approxHighBitsN) + a[1] = (a[1] >> approxLowBitsN) | ((a[2]) << approxHighBitsN) + a[2] = (a[2] >> approxLowBitsN) | ((a[3]) << approxHighBitsN) + a[3] = (a[3] >> approxLowBitsN) | ((a[4]) << approxHighBitsN) + a[4] = (a[4] >> approxLowBitsN) | ((a[5]) << approxHighBitsN) + a[5] = (a[5] >> approxLowBitsN) | (aHi << approxHighBitsN) + + var f1 int64 + // from this point on c1 aliases for g0 + f1, c1 = updateFactorsDecompose(c1) + bHi := b.linearCombNonModular(&s, f1, &b, c1) + if bHi&signBitSelector != 0 { + // if bHi < 0 + f1, c1 = -f1, -c1 + bHi = negL(&b, bHi) + } + // right-shift b by k-1 bits + b[0] = (b[0] >> approxLowBitsN) | ((b[1]) << approxHighBitsN) + b[1] = (b[1] >> approxLowBitsN) | ((b[2]) << approxHighBitsN) + b[2] = (b[2] >> approxLowBitsN) | ((b[3]) << approxHighBitsN) + b[3] = (b[3] >> approxLowBitsN) | ((b[4]) << approxHighBitsN) + b[4] = (b[4] >> approxLowBitsN) | ((b[5]) << approxHighBitsN) + b[5] = (b[5] >> approxLowBitsN) | (bHi << approxHighBitsN) + + if i&1 == 1 { + // Combine current update factors with previously stored ones + // [F₀, G₀; F₁, G₁] ← [f₀, g₀; f₁, g₁] [pf₀, pg₀; pf₁, pg₁], with capital letters denoting new combined values + // We get |F₀| = | f₀pf₀ + g₀pf₁ | ≤ |f₀pf₀| + |g₀pf₁| = |f₀| |pf₀| + |g₀| |pf₁| ≤ 2ᵏ⁻¹|pf₀| + 2ᵏ⁻¹|pf₁| + // = 2ᵏ⁻¹ (|pf₀| + |pf₁|) < 2ᵏ⁻¹ 2ᵏ = 2²ᵏ⁻¹ + // So |F₀| < 2²ᵏ⁻¹ meaning it fits in a 2k-bit signed register + + // c₀ aliases f₀, c₁ aliases g₁ + c0, g0, f1, c1 = c0*pf0+g0*pf1, + c0*pg0+g0*pg1, + f1*pf0+c1*pf1, + f1*pg0+c1*pg1 + + s = u + + // 0 ≤ u, v < 2²⁵⁵ + // |F₀|, |G₀| < 2⁶³ + u.linearComb(&u, c0, &v, g0) + // |F₁|, |G₁| < 2⁶³ + v.linearComb(&s, f1, &v, c1) + + } else { + // Save update factors + pf0, pg0, pf1, pg1 = c0, g0, f1, c1 + } + } + + // For every iteration that we miss, v is not being multiplied by 2ᵏ⁻² + const pSq uint64 = 1 << (2 * (k - 1)) + a = Element{pSq} + // If the function is constant-time ish, this loop will not run (no need to take it out explicitly) + for ; i < invIterationsN; i += 2 { + // could optimize further with mul by word routine or by pre-computing a table since with k=26, + // we would multiply by pSq up to 13times; + // on x86, the assembly routine outperforms generic code for mul by word + // on arm64, we may loose up to ~5% for 6 limbs + v.Mul(&v, &a) + } + + u.Set(x) // for correctness check + + z.Mul(&v, &Element{ + inversionCorrectionFactorWord0, + inversionCorrectionFactorWord1, + inversionCorrectionFactorWord2, + inversionCorrectionFactorWord3, + inversionCorrectionFactorWord4, + inversionCorrectionFactorWord5, + }) + + // correctness check + v.Mul(&u, z) + if !v.IsOne() && !u.IsZero() { + return z.inverseExp(u) + } + + return z +} + +// inverseExp computes z = x⁻¹ (mod q) = x**(q-2) (mod q) +func (z *Element) inverseExp(x Element) *Element { + // e == q-2 + e := Modulus() + e.Sub(e, big.NewInt(2)) + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// approximate a big number x into a single 64 bit word using its uppermost and lowermost bits +// if x fits in a word as is, no approximation necessary +func approximate(x *Element, nBits int) uint64 { + + if nBits <= 64 { + return x[0] + } + + const mask = (uint64(1) << (k - 1)) - 1 // k-1 ones + lo := mask & x[0] + + hiWordIndex := (nBits - 1) / 64 + + hiWordBitsAvailable := nBits - hiWordIndex*64 + hiWordBitsUsed := min(hiWordBitsAvailable, approxHighBitsN) + + mask_ := uint64(^((1 << (hiWordBitsAvailable - hiWordBitsUsed)) - 1)) + hi := (x[hiWordIndex] & mask_) << (64 - hiWordBitsAvailable) + + mask_ = ^(1<<(approxLowBitsN+hiWordBitsUsed) - 1) + mid := (mask_ & x[hiWordIndex-1]) >> hiWordBitsUsed + + return lo | mid | hi +} + +// linearComb z = xC * x + yC * y; +// 0 ≤ x, y < 2³⁷⁷ +// |xC|, |yC| < 2⁶³ +func (z *Element) linearComb(x *Element, xC int64, y *Element, yC int64) { + // | (hi, z) | < 2 * 2⁶³ * 2³⁷⁷ = 2⁴⁴¹ + // therefore | hi | < 2⁵⁷ ≤ 2⁶³ + hi := z.linearCombNonModular(x, xC, y, yC) + z.montReduceSigned(z, hi) +} + +// montReduceSigned z = (xHi * r + x) * r⁻¹ using the SOS algorithm +// Requires |xHi| < 2⁶³. Most significant bit of xHi is the sign bit. +func (z *Element) montReduceSigned(x *Element, xHi uint64) { + const signBitRemover = ^signBitSelector + mustNeg := xHi&signBitSelector != 0 + // the SOS implementation requires that most significant bit is 0 + // Let X be xHi*r + x + // If X is negative we would have initially stored it as 2⁶⁴ r + X (à la 2's complement) + xHi &= signBitRemover + // with this a negative X is now represented as 2⁶³ r + X + + var t [2*Limbs - 1]uint64 + var C uint64 + + m := x[0] * qInvNeg + + C = madd0(m, q0, x[0]) + C, t[1] = madd2(m, q1, x[1], C) + C, t[2] = madd2(m, q2, x[2], C) + C, t[3] = madd2(m, q3, x[3], C) + C, t[4] = madd2(m, q4, x[4], C) + C, t[5] = madd2(m, q5, x[5], C) + + // m * qElement[5] ≤ (2⁶⁴ - 1) * (2⁶³ - 1) = 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + // x[5] + C ≤ 2*(2⁶⁴ - 1) = 2⁶⁵ - 2 + // On LHS, (C, t[5]) ≤ 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + 2⁶⁵ - 2 = 2¹²⁷ + 2⁶³ - 1 + // So on LHS, C ≤ 2⁶³ + t[6] = xHi + C + // xHi + C < 2⁶³ + 2⁶³ = 2⁶⁴ + + // + { + const i = 1 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 2 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 3 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 4 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 5 + m := t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, z[0] = madd2(m, q1, t[i+1], C) + C, z[1] = madd2(m, q2, t[i+2], C) + C, z[2] = madd2(m, q3, t[i+3], C) + C, z[3] = madd2(m, q4, t[i+4], C) + z[5], z[4] = madd2(m, q5, t[i+5], C) + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + // + + if mustNeg { + // We have computed ( 2⁶³ r + X ) r⁻¹ = 2⁶³ + X r⁻¹ instead + var b uint64 + z[0], b = bits.Sub64(z[0], signBitSelector, 0) + z[1], b = bits.Sub64(z[1], 0, b) + z[2], b = bits.Sub64(z[2], 0, b) + z[3], b = bits.Sub64(z[3], 0, b) + z[4], b = bits.Sub64(z[4], 0, b) + z[5], b = bits.Sub64(z[5], 0, b) + + // Occurs iff x == 0 && xHi < 0, i.e. X = rX' for -2⁶³ ≤ X' < 0 + + if b != 0 { + // z[5] = -1 + // negative: add q + const neg1 = 0xFFFFFFFFFFFFFFFF + + var carry uint64 + + z[0], carry = bits.Add64(z[0], q0, 0) + z[1], carry = bits.Add64(z[1], q1, carry) + z[2], carry = bits.Add64(z[2], q2, carry) + z[3], carry = bits.Add64(z[3], q3, carry) + z[4], carry = bits.Add64(z[4], q4, carry) + z[5], _ = bits.Add64(neg1, q5, carry) + } + } +} + +const ( + updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) + updateFactorIdentityMatrixRow0 = 1 + updateFactorIdentityMatrixRow1 = 1 << 32 +) + +func updateFactorsDecompose(c int64) (int64, int64) { + c += updateFactorsConversionBias + const low32BitsFilter int64 = 0xFFFFFFFF + f := c&low32BitsFilter - 0x7FFFFFFF + g := c>>32&low32BitsFilter - 0x7FFFFFFF + return f, g +} + +// negL negates in place [x | xHi] and return the new most significant word xHi +func negL(x *Element, xHi uint64) uint64 { + var b uint64 + + x[0], b = bits.Sub64(0, x[0], 0) + x[1], b = bits.Sub64(0, x[1], b) + x[2], b = bits.Sub64(0, x[2], b) + x[3], b = bits.Sub64(0, x[3], b) + x[4], b = bits.Sub64(0, x[4], b) + x[5], b = bits.Sub64(0, x[5], b) + xHi, _ = bits.Sub64(0, xHi, b) + + return xHi +} + +// mulWNonModular multiplies by one word in non-montgomery, without reducing +func (z *Element) mulWNonModular(x *Element, y int64) uint64 { + + // w := abs(y) + m := y >> 63 + w := uint64((y ^ m) - m) + + var c uint64 + c, z[0] = bits.Mul64(x[0], w) + c, z[1] = madd1(x[1], w, c) + c, z[2] = madd1(x[2], w, c) + c, z[3] = madd1(x[3], w, c) + c, z[4] = madd1(x[4], w, c) + c, z[5] = madd1(x[5], w, c) + + if y < 0 { + c = negL(z, c) + } + + return c +} + +// linearCombNonModular computes a linear combination without modular reduction +func (z *Element) linearCombNonModular(x *Element, xC int64, y *Element, yC int64) uint64 { + var yTimes Element + + yHi := yTimes.mulWNonModular(y, yC) + xHi := z.mulWNonModular(x, xC) + + var carry uint64 + z[0], carry = bits.Add64(z[0], yTimes[0], 0) + z[1], carry = bits.Add64(z[1], yTimes[1], carry) + z[2], carry = bits.Add64(z[2], yTimes[2], carry) + z[3], carry = bits.Add64(z[3], yTimes[3], carry) + z[4], carry = bits.Add64(z[4], yTimes[4], carry) + z[5], carry = bits.Add64(z[5], yTimes[5], carry) + + yHi, _ = bits.Add64(xHi, yHi, carry) + + return yHi +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_exp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_exp.go new file mode 100644 index 00000000000..e3d936dfc19 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_exp.go @@ -0,0 +1,992 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +// expBySqrtExp is equivalent to z.Exp(x, 35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a11) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expBySqrtExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _100 = 1 + _11 + // _101 = 1 + _100 + // _111 = _10 + _101 + // _1001 = _10 + _111 + // _1011 = _10 + _1001 + // _1111 = _100 + _1011 + // _10001 = _10 + _1111 + // _10011 = _10 + _10001 + // _10111 = _100 + _10011 + // _11011 = _100 + _10111 + // _11101 = _10 + _11011 + // _11111 = _10 + _11101 + // _110100 = _10111 + _11101 + // _11010000 = _110100 << 2 + // _11010111 = _111 + _11010000 + // i36 = 2*((_11010111 << 8 + _11101) << 7 + _10001) + // i50 = ((1 + i36) << 9 + _10111) << 2 + _11 + // i71 = ((i50 << 6 + _101) << 4 + 1) << 9 + // i84 = ((_11101 + i71) << 5 + _1011) << 5 + _11 + // i105 = (2*(i84 << 8 + _11101) + 1) << 10 + // i125 = ((_10111 + i105) << 12 + _11011) << 5 + _101 + // i147 = ((i125 << 7 + _101) << 6 + _1001) << 7 + // i158 = ((_11101 + i147) << 5 + _10001) << 3 + _101 + // i181 = ((i158 << 8 + _10001) << 6 + _11011) << 7 + // i200 = ((_11111 + i181) << 4 + _11) << 12 + _1111 + // i219 = ((i200 << 4 + _101) << 8 + _10011) << 5 + // i232 = ((_10001 + i219) << 3 + _111) << 7 + _1111 + // i254 = ((i232 << 5 + _1111) << 7 + _11011) << 8 + // i269 = ((_10001 + i254) << 6 + _11111) << 6 + _11101 + // i304 = ((i269 << 9 + _1001) << 5 + _1001) << 19 + // i321 = ((_10111 + i304) << 8 + _1011) << 6 + _10111 + // i337 = ((i321 << 4 + _101) << 4 + 1) << 6 + // i376 = ((_11 + i337) << 29 + 1) << 7 + _101 + // return i376 << 9 + _10001 + // + // Operations: 325 squares 61 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11 Element + // Step 1: t6 = x^0x2 + t6.Square(&x) + + // Step 2: t1 = x^0x3 + t1.Mul(&x, t6) + + // Step 3: t5 = x^0x4 + t5.Mul(&x, t1) + + // Step 4: t0 = x^0x5 + t0.Mul(&x, t5) + + // Step 5: t9 = x^0x7 + t9.Mul(t6, t0) + + // Step 6: t4 = x^0x9 + t4.Mul(t6, t9) + + // Step 7: t3 = x^0xb + t3.Mul(t6, t4) + + // Step 8: t8 = x^0xf + t8.Mul(t5, t3) + + // Step 9: z = x^0x11 + z.Mul(t6, t8) + + // Step 10: t10 = x^0x13 + t10.Mul(t6, z) + + // Step 11: t2 = x^0x17 + t2.Mul(t5, t10) + + // Step 12: t7 = x^0x1b + t7.Mul(t5, t2) + + // Step 13: t5 = x^0x1d + t5.Mul(t6, t7) + + // Step 14: t6 = x^0x1f + t6.Mul(t6, t5) + + // Step 15: t11 = x^0x34 + t11.Mul(t2, t5) + + // Step 17: t11 = x^0xd0 + for s := 0; s < 2; s++ { + t11.Square(t11) + } + + // Step 18: t11 = x^0xd7 + t11.Mul(t9, t11) + + // Step 26: t11 = x^0xd700 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 27: t11 = x^0xd71d + t11.Mul(t5, t11) + + // Step 34: t11 = x^0x6b8e80 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 35: t11 = x^0x6b8e91 + t11.Mul(z, t11) + + // Step 36: t11 = x^0xd71d22 + t11.Square(t11) + + // Step 37: t11 = x^0xd71d23 + t11.Mul(&x, t11) + + // Step 46: t11 = x^0x1ae3a4600 + for s := 0; s < 9; s++ { + t11.Square(t11) + } + + // Step 47: t11 = x^0x1ae3a4617 + t11.Mul(t2, t11) + + // Step 49: t11 = x^0x6b8e9185c + for s := 0; s < 2; s++ { + t11.Square(t11) + } + + // Step 50: t11 = x^0x6b8e9185f + t11.Mul(t1, t11) + + // Step 56: t11 = x^0x1ae3a4617c0 + for s := 0; s < 6; s++ { + t11.Square(t11) + } + + // Step 57: t11 = x^0x1ae3a4617c5 + t11.Mul(t0, t11) + + // Step 61: t11 = x^0x1ae3a4617c50 + for s := 0; s < 4; s++ { + t11.Square(t11) + } + + // Step 62: t11 = x^0x1ae3a4617c51 + t11.Mul(&x, t11) + + // Step 71: t11 = x^0x35c748c2f8a200 + for s := 0; s < 9; s++ { + t11.Square(t11) + } + + // Step 72: t11 = x^0x35c748c2f8a21d + t11.Mul(t5, t11) + + // Step 77: t11 = x^0x6b8e9185f1443a0 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 78: t11 = x^0x6b8e9185f1443ab + t11.Mul(t3, t11) + + // Step 83: t11 = x^0xd71d230be2887560 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 84: t11 = x^0xd71d230be2887563 + t11.Mul(t1, t11) + + // Step 92: t11 = x^0xd71d230be288756300 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 93: t11 = x^0xd71d230be28875631d + t11.Mul(t5, t11) + + // Step 94: t11 = x^0x1ae3a4617c510eac63a + t11.Square(t11) + + // Step 95: t11 = x^0x1ae3a4617c510eac63b + t11.Mul(&x, t11) + + // Step 105: t11 = x^0x6b8e9185f1443ab18ec00 + for s := 0; s < 10; s++ { + t11.Square(t11) + } + + // Step 106: t11 = x^0x6b8e9185f1443ab18ec17 + t11.Mul(t2, t11) + + // Step 118: t11 = x^0x6b8e9185f1443ab18ec17000 + for s := 0; s < 12; s++ { + t11.Square(t11) + } + + // Step 119: t11 = x^0x6b8e9185f1443ab18ec1701b + t11.Mul(t7, t11) + + // Step 124: t11 = x^0xd71d230be28875631d82e0360 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 125: t11 = x^0xd71d230be28875631d82e0365 + t11.Mul(t0, t11) + + // Step 132: t11 = x^0x6b8e9185f1443ab18ec1701b280 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 133: t11 = x^0x6b8e9185f1443ab18ec1701b285 + t11.Mul(t0, t11) + + // Step 139: t11 = x^0x1ae3a4617c510eac63b05c06ca140 + for s := 0; s < 6; s++ { + t11.Square(t11) + } + + // Step 140: t11 = x^0x1ae3a4617c510eac63b05c06ca149 + t11.Mul(t4, t11) + + // Step 147: t11 = x^0xd71d230be28875631d82e03650a480 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 148: t11 = x^0xd71d230be28875631d82e03650a49d + t11.Mul(t5, t11) + + // Step 153: t11 = x^0x1ae3a4617c510eac63b05c06ca1493a0 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 154: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1 + t11.Mul(z, t11) + + // Step 157: t11 = x^0xd71d230be28875631d82e03650a49d88 + for s := 0; s < 3; s++ { + t11.Square(t11) + } + + // Step 158: t11 = x^0xd71d230be28875631d82e03650a49d8d + t11.Mul(t0, t11) + + // Step 166: t11 = x^0xd71d230be28875631d82e03650a49d8d00 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 167: t11 = x^0xd71d230be28875631d82e03650a49d8d11 + t11.Mul(z, t11) + + // Step 173: t11 = x^0x35c748c2f8a21d58c760b80d942927634440 + for s := 0; s < 6; s++ { + t11.Square(t11) + } + + // Step 174: t11 = x^0x35c748c2f8a21d58c760b80d94292763445b + t11.Mul(t7, t11) + + // Step 181: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d80 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 182: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f + t11.Mul(t6, t11) + + // Step 186: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f0 + for s := 0; s < 4; s++ { + t11.Square(t11) + } + + // Step 187: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f3 + t11.Mul(t1, t11) + + // Step 199: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f3000 + for s := 0; s < 12; s++ { + t11.Square(t11) + } + + // Step 200: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f + t11.Mul(t8, t11) + + // Step 204: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f0 + for s := 0; s < 4; s++ { + t11.Square(t11) + } + + // Step 205: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5 + t11.Mul(t0, t11) + + // Step 213: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f500 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 214: t10 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f513 + t10.Mul(t10, t11) + + // Step 219: t10 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea260 + for s := 0; s < 5; s++ { + t10.Square(t10) + } + + // Step 220: t10 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271 + t10.Mul(z, t10) + + // Step 223: t10 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f51388 + for s := 0; s < 3; s++ { + t10.Square(t10) + } + + // Step 224: t9 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f + t9.Mul(t9, t10) + + // Step 231: t9 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c780 + for s := 0; s < 7; s++ { + t9.Square(t9) + } + + // Step 232: t9 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f + t9.Mul(t8, t9) + + // Step 237: t9 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1e0 + for s := 0; s < 5; s++ { + t9.Square(t9) + } + + // Step 238: t8 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef + t8.Mul(t8, t9) + + // Step 245: t8 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f780 + for s := 0; s < 7; s++ { + t8.Square(t8) + } + + // Step 246: t7 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b + t7.Mul(t7, t8) + + // Step 254: t7 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b00 + for s := 0; s < 8; s++ { + t7.Square(t7) + } + + // Step 255: t7 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b11 + t7.Mul(z, t7) + + // Step 261: t7 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c440 + for s := 0; s < 6; s++ { + t7.Square(t7) + } + + // Step 262: t6 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f + t6.Mul(t6, t7) + + // Step 268: t6 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b117c0 + for s := 0; s < 6; s++ { + t6.Square(t6) + } + + // Step 269: t5 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b117dd + t5.Mul(t5, t6) + + // Step 278: t5 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba00 + for s := 0; s < 9; s++ { + t5.Square(t5) + } + + // Step 279: t5 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba09 + t5.Mul(t4, t5) + + // Step 284: t5 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f74120 + for s := 0; s < 5; s++ { + t5.Square(t5) + } + + // Step 285: t4 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f74129 + t4.Mul(t4, t5) + + // Step 304: t4 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba09480000 + for s := 0; s < 19; s++ { + t4.Square(t4) + } + + // Step 305: t4 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba09480017 + t4.Mul(t2, t4) + + // Step 313: t4 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba0948001700 + for s := 0; s < 8; s++ { + t4.Square(t4) + } + + // Step 314: t3 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b + t3.Mul(t3, t4) + + // Step 320: t3 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2c0 + for s := 0; s < 6; s++ { + t3.Square(t3) + } + + // Step 321: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d7 + t2.Mul(t2, t3) + + // Step 325: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d70 + for s := 0; s < 4; s++ { + t2.Square(t2) + } + + // Step 326: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d75 + t2.Mul(t0, t2) + + // Step 330: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d750 + for s := 0; s < 4; s++ { + t2.Square(t2) + } + + // Step 331: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d751 + t2.Mul(&x, t2) + + // Step 337: t2 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d440 + for s := 0; s < 6; s++ { + t2.Square(t2) + } + + // Step 338: t1 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d443 + t1.Mul(t1, t2) + + // Step 367: t1 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba8860000000 + for s := 0; s < 29; s++ { + t1.Square(t1) + } + + // Step 368: t1 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba8860000001 + t1.Mul(&x, t1) + + // Step 375: t1 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d443000000080 + for s := 0; s < 7; s++ { + t1.Square(t1) + } + + // Step 376: t0 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d443000000085 + t0.Mul(t0, t1) + + // Step 385: t0 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a00 + for s := 0; s < 9; s++ { + t0.Square(t0) + } + + // Step 386: z = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a11 + z.Mul(z, t0) + + return z +} + +// expByLegendreExp is equivalent to z.Exp(x, d71d230be28875631d82e03650a49d8d116cf9807a89c78f79b117dd04a4000b85aea2180000004284600000000000) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expByLegendreExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _100 = 1 + _11 + // _101 = 1 + _100 + // _111 = _10 + _101 + // _1001 = _10 + _111 + // _1011 = _10 + _1001 + // _1111 = _100 + _1011 + // _10001 = _10 + _1111 + // _10011 = _10 + _10001 + // _10111 = _100 + _10011 + // _11011 = _100 + _10111 + // _11101 = _10 + _11011 + // _11111 = _10 + _11101 + // _110100 = _10111 + _11101 + // _11010000 = _110100 << 2 + // _11010111 = _111 + _11010000 + // i36 = 2*((_11010111 << 8 + _11101) << 7 + _10001) + // i50 = ((1 + i36) << 9 + _10111) << 2 + _11 + // i71 = ((i50 << 6 + _101) << 4 + 1) << 9 + // i84 = ((_11101 + i71) << 5 + _1011) << 5 + _11 + // i105 = (2*(i84 << 8 + _11101) + 1) << 10 + // i125 = ((_10111 + i105) << 12 + _11011) << 5 + _101 + // i147 = ((i125 << 7 + _101) << 6 + _1001) << 7 + // i158 = ((_11101 + i147) << 5 + _10001) << 3 + _101 + // i181 = ((i158 << 8 + _10001) << 6 + _11011) << 7 + // i200 = ((_11111 + i181) << 4 + _11) << 12 + _1111 + // i219 = ((i200 << 4 + _101) << 8 + _10011) << 5 + // i232 = ((_10001 + i219) << 3 + _111) << 7 + _1111 + // i254 = ((i232 << 5 + _1111) << 7 + _11011) << 8 + // i269 = ((_10001 + i254) << 6 + _11111) << 6 + _11101 + // i304 = ((i269 << 9 + _1001) << 5 + _1001) << 19 + // i321 = ((_10111 + i304) << 8 + _1011) << 6 + _10111 + // i337 = ((i321 << 4 + _101) << 4 + 1) << 6 + // i376 = ((_11 + i337) << 29 + 1) << 7 + _101 + // return (2*(i376 << 9 + _10001) + 1) << 45 + // + // Operations: 371 squares 62 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11 Element + // Step 1: t6 = x^0x2 + t6.Square(&x) + + // Step 2: t1 = x^0x3 + t1.Mul(&x, t6) + + // Step 3: t5 = x^0x4 + t5.Mul(&x, t1) + + // Step 4: t0 = x^0x5 + t0.Mul(&x, t5) + + // Step 5: t9 = x^0x7 + t9.Mul(t6, t0) + + // Step 6: t4 = x^0x9 + t4.Mul(t6, t9) + + // Step 7: t3 = x^0xb + t3.Mul(t6, t4) + + // Step 8: t8 = x^0xf + t8.Mul(t5, t3) + + // Step 9: z = x^0x11 + z.Mul(t6, t8) + + // Step 10: t10 = x^0x13 + t10.Mul(t6, z) + + // Step 11: t2 = x^0x17 + t2.Mul(t5, t10) + + // Step 12: t7 = x^0x1b + t7.Mul(t5, t2) + + // Step 13: t5 = x^0x1d + t5.Mul(t6, t7) + + // Step 14: t6 = x^0x1f + t6.Mul(t6, t5) + + // Step 15: t11 = x^0x34 + t11.Mul(t2, t5) + + // Step 17: t11 = x^0xd0 + for s := 0; s < 2; s++ { + t11.Square(t11) + } + + // Step 18: t11 = x^0xd7 + t11.Mul(t9, t11) + + // Step 26: t11 = x^0xd700 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 27: t11 = x^0xd71d + t11.Mul(t5, t11) + + // Step 34: t11 = x^0x6b8e80 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 35: t11 = x^0x6b8e91 + t11.Mul(z, t11) + + // Step 36: t11 = x^0xd71d22 + t11.Square(t11) + + // Step 37: t11 = x^0xd71d23 + t11.Mul(&x, t11) + + // Step 46: t11 = x^0x1ae3a4600 + for s := 0; s < 9; s++ { + t11.Square(t11) + } + + // Step 47: t11 = x^0x1ae3a4617 + t11.Mul(t2, t11) + + // Step 49: t11 = x^0x6b8e9185c + for s := 0; s < 2; s++ { + t11.Square(t11) + } + + // Step 50: t11 = x^0x6b8e9185f + t11.Mul(t1, t11) + + // Step 56: t11 = x^0x1ae3a4617c0 + for s := 0; s < 6; s++ { + t11.Square(t11) + } + + // Step 57: t11 = x^0x1ae3a4617c5 + t11.Mul(t0, t11) + + // Step 61: t11 = x^0x1ae3a4617c50 + for s := 0; s < 4; s++ { + t11.Square(t11) + } + + // Step 62: t11 = x^0x1ae3a4617c51 + t11.Mul(&x, t11) + + // Step 71: t11 = x^0x35c748c2f8a200 + for s := 0; s < 9; s++ { + t11.Square(t11) + } + + // Step 72: t11 = x^0x35c748c2f8a21d + t11.Mul(t5, t11) + + // Step 77: t11 = x^0x6b8e9185f1443a0 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 78: t11 = x^0x6b8e9185f1443ab + t11.Mul(t3, t11) + + // Step 83: t11 = x^0xd71d230be2887560 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 84: t11 = x^0xd71d230be2887563 + t11.Mul(t1, t11) + + // Step 92: t11 = x^0xd71d230be288756300 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 93: t11 = x^0xd71d230be28875631d + t11.Mul(t5, t11) + + // Step 94: t11 = x^0x1ae3a4617c510eac63a + t11.Square(t11) + + // Step 95: t11 = x^0x1ae3a4617c510eac63b + t11.Mul(&x, t11) + + // Step 105: t11 = x^0x6b8e9185f1443ab18ec00 + for s := 0; s < 10; s++ { + t11.Square(t11) + } + + // Step 106: t11 = x^0x6b8e9185f1443ab18ec17 + t11.Mul(t2, t11) + + // Step 118: t11 = x^0x6b8e9185f1443ab18ec17000 + for s := 0; s < 12; s++ { + t11.Square(t11) + } + + // Step 119: t11 = x^0x6b8e9185f1443ab18ec1701b + t11.Mul(t7, t11) + + // Step 124: t11 = x^0xd71d230be28875631d82e0360 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 125: t11 = x^0xd71d230be28875631d82e0365 + t11.Mul(t0, t11) + + // Step 132: t11 = x^0x6b8e9185f1443ab18ec1701b280 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 133: t11 = x^0x6b8e9185f1443ab18ec1701b285 + t11.Mul(t0, t11) + + // Step 139: t11 = x^0x1ae3a4617c510eac63b05c06ca140 + for s := 0; s < 6; s++ { + t11.Square(t11) + } + + // Step 140: t11 = x^0x1ae3a4617c510eac63b05c06ca149 + t11.Mul(t4, t11) + + // Step 147: t11 = x^0xd71d230be28875631d82e03650a480 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 148: t11 = x^0xd71d230be28875631d82e03650a49d + t11.Mul(t5, t11) + + // Step 153: t11 = x^0x1ae3a4617c510eac63b05c06ca1493a0 + for s := 0; s < 5; s++ { + t11.Square(t11) + } + + // Step 154: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1 + t11.Mul(z, t11) + + // Step 157: t11 = x^0xd71d230be28875631d82e03650a49d88 + for s := 0; s < 3; s++ { + t11.Square(t11) + } + + // Step 158: t11 = x^0xd71d230be28875631d82e03650a49d8d + t11.Mul(t0, t11) + + // Step 166: t11 = x^0xd71d230be28875631d82e03650a49d8d00 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 167: t11 = x^0xd71d230be28875631d82e03650a49d8d11 + t11.Mul(z, t11) + + // Step 173: t11 = x^0x35c748c2f8a21d58c760b80d942927634440 + for s := 0; s < 6; s++ { + t11.Square(t11) + } + + // Step 174: t11 = x^0x35c748c2f8a21d58c760b80d94292763445b + t11.Mul(t7, t11) + + // Step 181: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d80 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 182: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f + t11.Mul(t6, t11) + + // Step 186: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f0 + for s := 0; s < 4; s++ { + t11.Square(t11) + } + + // Step 187: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f3 + t11.Mul(t1, t11) + + // Step 199: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f3000 + for s := 0; s < 12; s++ { + t11.Square(t11) + } + + // Step 200: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f + t11.Mul(t8, t11) + + // Step 204: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f0 + for s := 0; s < 4; s++ { + t11.Square(t11) + } + + // Step 205: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5 + t11.Mul(t0, t11) + + // Step 213: t11 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f500 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 214: t10 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f513 + t10.Mul(t10, t11) + + // Step 219: t10 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea260 + for s := 0; s < 5; s++ { + t10.Square(t10) + } + + // Step 220: t10 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271 + t10.Mul(z, t10) + + // Step 223: t10 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f51388 + for s := 0; s < 3; s++ { + t10.Square(t10) + } + + // Step 224: t9 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f + t9.Mul(t9, t10) + + // Step 231: t9 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c780 + for s := 0; s < 7; s++ { + t9.Square(t9) + } + + // Step 232: t9 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f + t9.Mul(t8, t9) + + // Step 237: t9 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1e0 + for s := 0; s < 5; s++ { + t9.Square(t9) + } + + // Step 238: t8 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef + t8.Mul(t8, t9) + + // Step 245: t8 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f780 + for s := 0; s < 7; s++ { + t8.Square(t8) + } + + // Step 246: t7 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b + t7.Mul(t7, t8) + + // Step 254: t7 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b00 + for s := 0; s < 8; s++ { + t7.Square(t7) + } + + // Step 255: t7 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b11 + t7.Mul(z, t7) + + // Step 261: t7 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c440 + for s := 0; s < 6; s++ { + t7.Square(t7) + } + + // Step 262: t6 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f + t6.Mul(t6, t7) + + // Step 268: t6 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b117c0 + for s := 0; s < 6; s++ { + t6.Square(t6) + } + + // Step 269: t5 = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b117dd + t5.Mul(t5, t6) + + // Step 278: t5 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba00 + for s := 0; s < 9; s++ { + t5.Square(t5) + } + + // Step 279: t5 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba09 + t5.Mul(t4, t5) + + // Step 284: t5 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f74120 + for s := 0; s < 5; s++ { + t5.Square(t5) + } + + // Step 285: t4 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f74129 + t4.Mul(t4, t5) + + // Step 304: t4 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba09480000 + for s := 0; s < 19; s++ { + t4.Square(t4) + } + + // Step 305: t4 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba09480017 + t4.Mul(t2, t4) + + // Step 313: t4 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba0948001700 + for s := 0; s < 8; s++ { + t4.Square(t4) + } + + // Step 314: t3 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b + t3.Mul(t3, t4) + + // Step 320: t3 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2c0 + for s := 0; s < 6; s++ { + t3.Square(t3) + } + + // Step 321: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d7 + t2.Mul(t2, t3) + + // Step 325: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d70 + for s := 0; s < 4; s++ { + t2.Square(t2) + } + + // Step 326: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d75 + t2.Mul(t0, t2) + + // Step 330: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d750 + for s := 0; s < 4; s++ { + t2.Square(t2) + } + + // Step 331: t2 = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d751 + t2.Mul(&x, t2) + + // Step 337: t2 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d440 + for s := 0; s < 6; s++ { + t2.Square(t2) + } + + // Step 338: t1 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d443 + t1.Mul(t1, t2) + + // Step 367: t1 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba8860000000 + for s := 0; s < 29; s++ { + t1.Square(t1) + } + + // Step 368: t1 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba8860000001 + t1.Mul(&x, t1) + + // Step 375: t1 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d443000000080 + for s := 0; s < 7; s++ { + t1.Square(t1) + } + + // Step 376: t0 = x^0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d443000000085 + t0.Mul(t0, t1) + + // Step 385: t0 = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a00 + for s := 0; s < 9; s++ { + t0.Square(t0) + } + + // Step 386: z = x^0x35c748c2f8a21d58c760b80d94292763445b3e601ea271e3de6c45f741290002e16ba88600000010a11 + z.Mul(z, t0) + + // Step 387: z = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d7510c00000021422 + z.Square(z) + + // Step 388: z = x^0x6b8e9185f1443ab18ec1701b28524ec688b67cc03d44e3c7bcd88bee82520005c2d7510c00000021423 + z.Mul(&x, z) + + // Step 433: z = x^0xd71d230be28875631d82e03650a49d8d116cf9807a89c78f79b117dd04a4000b85aea2180000004284600000000000 + for s := 0; s < 45; s++ { + z.Square(z) + } + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_amd64.s new file mode 100644 index 00000000000..3e7650e5aab --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_mul_amd64.s @@ -0,0 +1,857 @@ +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x8508c00000000001 +DATA q<>+8(SB)/8, $0x170b5d4430000000 +DATA q<>+16(SB)/8, $0x1ef3622fba094800 +DATA q<>+24(SB)/8, $0x1a22d9f300f5138f +DATA q<>+32(SB)/8, $0xc63b05c06ca1493b +DATA q<>+40(SB)/8, $0x01ae3a4617c510ea +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x8508bfffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +// mul(res, x, y *Element) +TEXT ·mul(SB), $24-24 + + // the algorithm is described in the Element.Mul declaration (.go) + // however, to benefit from the ADCX and ADOX carry chains + // we split the inner loops in 2: + // for i=0 to N-1 + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + A + + NO_LOCAL_POINTERS + CMPB ·supportAdx(SB), $1 + JNE l1 + MOVQ x+8(FP), R8 + + // x[0] -> R10 + // x[1] -> R11 + // x[2] -> R12 + MOVQ 0(R8), R10 + MOVQ 8(R8), R11 + MOVQ 16(R8), R12 + MOVQ y+16(FP), R13 + + // A -> BP + // t[0] -> R14 + // t[1] -> R15 + // t[2] -> CX + // t[3] -> BX + // t[4] -> SI + // t[5] -> DI + // clear the flags + XORQ AX, AX + MOVQ 0(R13), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R10, R14, R15 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R11, AX, CX + ADOXQ AX, R15 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ R12, AX, BX + ADOXQ AX, CX + + // (A,t[3]) := x[3]*y[0] + A + MULXQ 24(R8), AX, SI + ADOXQ AX, BX + + // (A,t[4]) := x[4]*y[0] + A + MULXQ 32(R8), AX, DI + ADOXQ AX, SI + + // (A,t[5]) := x[5]*y[0] + A + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 8(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 16(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 24(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 32(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 40(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R9,R8,R13,R10,R11,R12) + REDUCE(R14,R15,CX,BX,SI,DI,R9,R8,R13,R10,R11,R12) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET + +l1: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·_mulGeneric(SB) + RET + +TEXT ·fromMont(SB), $8-8 + NO_LOCAL_POINTERS + + // the algorithm is described here + // https://hackmd.io/@gnark/modular_multiplication + // when y = 1 we have: + // for i=0 to N-1 + // t[i] = x[i] + // for i=0 to N-1 + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + CMPB ·supportAdx(SB), $1 + JNE l2 + MOVQ res+0(FP), DX + MOVQ 0(DX), R14 + MOVQ 8(DX), R15 + MOVQ 16(DX), CX + MOVQ 24(DX), BX + MOVQ 32(DX), SI + MOVQ 40(DX), DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R8,R9,R10,R11,R12,R13) + REDUCE(R14,R15,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET + +l2: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + CALL ·_fromMontGeneric(SB) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.go new file mode 100644 index 00000000000..83bba45aedf --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.go @@ -0,0 +1,107 @@ +//go:build !purego +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +//go:noescape +func MulBy3(x *Element) + +//go:noescape +func MulBy5(x *Element) + +//go:noescape +func MulBy13(x *Element) + +//go:noescape +func mul(res, x, y *Element) + +//go:noescape +func fromMont(res *Element) + +//go:noescape +func reduce(res *Element) + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +// +//go:noescape +func Butterfly(a, b *Element) + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + mul(z, x, y) + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for doc. + mul(z, x, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.s new file mode 100644 index 00000000000..7242622a4a4 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_amd64.s @@ -0,0 +1,306 @@ +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x8508c00000000001 +DATA q<>+8(SB)/8, $0x170b5d4430000000 +DATA q<>+16(SB)/8, $0x1ef3622fba094800 +DATA q<>+24(SB)/8, $0x1a22d9f300f5138f +DATA q<>+32(SB)/8, $0xc63b05c06ca1493b +DATA q<>+40(SB)/8, $0x01ae3a4617c510ea +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x8508bfffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +TEXT ·reduce(SB), NOSPLIT, $0-8 + MOVQ res+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy3(x *Element) +TEXT ·MulBy3(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,R9,R10,R11,R12,R13) + REDUCE(DX,CX,BX,SI,DI,R8,R15,R9,R10,R11,R12,R13) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy5(x *Element) +TEXT ·MulBy5(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,R9,R10,R11,R12,R13) + REDUCE(DX,CX,BX,SI,DI,R8,R15,R9,R10,R11,R12,R13) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R14,R15,R9,R10,R11,R12) + REDUCE(DX,CX,BX,SI,DI,R8,R14,R15,R9,R10,R11,R12) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy13(x *Element) +TEXT ·MulBy13(SB), $40-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,s0-8(SP),s1-16(SP),s2-24(SP),s3-32(SP),s4-40(SP)) + REDUCE(DX,CX,BX,SI,DI,R8,R15,s0-8(SP),s1-16(SP),s2-24(SP),s3-32(SP),s4-40(SP)) + + MOVQ DX, R15 + MOVQ CX, s0-8(SP) + MOVQ BX, s1-16(SP) + MOVQ SI, s2-24(SP) + MOVQ DI, s3-32(SP) + MOVQ R8, s4-40(SP) + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ R15, DX + ADCQ s0-8(SP), CX + ADCQ s1-16(SP), BX + ADCQ s2-24(SP), SI + ADCQ s3-32(SP), DI + ADCQ s4-40(SP), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// Butterfly(a, b *Element) sets a = a + b; b = a - b +TEXT ·Butterfly(SB), $48-16 + MOVQ a+0(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ 32(AX), R8 + MOVQ 40(AX), R9 + MOVQ CX, R10 + MOVQ BX, R11 + MOVQ SI, R12 + MOVQ DI, R13 + MOVQ R8, R14 + MOVQ R9, R15 + XORQ AX, AX + MOVQ b+8(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + ADCQ 32(DX), R8 + ADCQ 40(DX), R9 + SUBQ 0(DX), R10 + SBBQ 8(DX), R11 + SBBQ 16(DX), R12 + SBBQ 24(DX), R13 + SBBQ 32(DX), R14 + SBBQ 40(DX), R15 + MOVQ CX, s0-8(SP) + MOVQ BX, s1-16(SP) + MOVQ SI, s2-24(SP) + MOVQ DI, s3-32(SP) + MOVQ R8, s4-40(SP) + MOVQ R9, s5-48(SP) + MOVQ $0x8508c00000000001, CX + MOVQ $0x170b5d4430000000, BX + MOVQ $0x1ef3622fba094800, SI + MOVQ $0x1a22d9f300f5138f, DI + MOVQ $0xc63b05c06ca1493b, R8 + MOVQ $0x01ae3a4617c510ea, R9 + CMOVQCC AX, CX + CMOVQCC AX, BX + CMOVQCC AX, SI + CMOVQCC AX, DI + CMOVQCC AX, R8 + CMOVQCC AX, R9 + ADDQ CX, R10 + ADCQ BX, R11 + ADCQ SI, R12 + ADCQ DI, R13 + ADCQ R8, R14 + ADCQ R9, R15 + MOVQ s0-8(SP), CX + MOVQ s1-16(SP), BX + MOVQ s2-24(SP), SI + MOVQ s3-32(SP), DI + MOVQ s4-40(SP), R8 + MOVQ s5-48(SP), R9 + MOVQ R10, 0(DX) + MOVQ R11, 8(DX) + MOVQ R12, 16(DX) + MOVQ R13, 24(DX) + MOVQ R14, 32(DX) + MOVQ R15, 40(DX) + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ a+0(FP), AX + MOVQ CX, 0(AX) + MOVQ BX, 8(AX) + MOVQ SI, 16(AX) + MOVQ DI, 24(AX) + MOVQ R8, 32(AX) + MOVQ R9, 40(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_purego.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_purego.go new file mode 100644 index 00000000000..a4c3796b96b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_ops_purego.go @@ -0,0 +1,745 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import "math/bits" + +// MulBy3 x *= 3 (mod q) +func MulBy3(x *Element) { + _x := *x + x.Double(x).Add(x, &_x) +} + +// MulBy5 x *= 5 (mod q) +func MulBy5(x *Element) { + _x := *x + x.Double(x).Double(x).Add(x, &_x) +} + +// MulBy13 x *= 13 (mod q) +func MulBy13(x *Element) { + var y = Element{ + 1176283927673829444, + 14130787773971430395, + 11354866436980285261, + 15740727779991009548, + 14951814113394531041, + 33013799364667434, + } + x.Mul(x, &y) +} + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + var t0, t1, t2, t3, t4, t5 uint64 + var u0, u1, u2, u3, u4, u5 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, y[0]) + u1, t1 = bits.Mul64(v, y[1]) + u2, t2 = bits.Mul64(v, y[2]) + u3, t3 = bits.Mul64(v, y[3]) + u4, t4 = bits.Mul64(v, y[4]) + u5, t5 = bits.Mul64(v, y[5]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[4] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[5] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + z[4] = t4 + z[5] = t5 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for algorithm documentation + + var t0, t1, t2, t3, t4, t5 uint64 + var u0, u1, u2, u3, u4, u5 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, x[0]) + u1, t1 = bits.Mul64(v, x[1]) + u2, t2 = bits.Mul64(v, x[2]) + u3, t3 = bits.Mul64(v, x[3]) + u4, t4 = bits.Mul64(v, x[4]) + u5, t5 = bits.Mul64(v, x[5]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[4] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[5] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + z[4] = t4 + z[5] = t5 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_utils.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_utils.go new file mode 100644 index 00000000000..6da4e95fd7a --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element_utils.go @@ -0,0 +1,29 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fp + +// MulByNonResidueInv ... +func (z *Element) MulByNonResidueInv(x *Element) *Element { + qnrInv := Element{ + 9255502405446297221, + 10229180150694123945, + 9215585410771530959, + 13357015519562362907, + 5437107869987383107, + 16259554076827459, + } + z.Mul(x, &qnrInv) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/vector.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/vector.go new file mode 100644 index 00000000000..3fe11371029 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/vector.go @@ -0,0 +1,255 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "runtime" + "strings" + "sync" + "sync/atomic" + "unsafe" +) + +// Vector represents a slice of Element. +// +// It implements the following interfaces: +// - Stringer +// - io.WriterTo +// - io.ReaderFrom +// - encoding.BinaryMarshaler +// - encoding.BinaryUnmarshaler +// - sort.Interface +type Vector []Element + +// MarshalBinary implements encoding.BinaryMarshaler +func (vector *Vector) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + + if _, err = vector.WriteTo(&buf); err != nil { + return + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (vector *Vector) UnmarshalBinary(data []byte) error { + r := bytes.NewReader(data) + _, err := vector.ReadFrom(r) + return err +} + +// WriteTo implements io.WriterTo and writes a vector of big endian encoded Element. +// Length of the vector is encoded as a uint32 on the first 4 bytes. +func (vector *Vector) WriteTo(w io.Writer) (int64, error) { + // encode slice length + if err := binary.Write(w, binary.BigEndian, uint32(len(*vector))); err != nil { + return 0, err + } + + n := int64(4) + + var buf [Bytes]byte + for i := 0; i < len(*vector); i++ { + BigEndian.PutElement(&buf, (*vector)[i]) + m, err := w.Write(buf[:]) + n += int64(m) + if err != nil { + return n, err + } + } + return n, nil +} + +// AsyncReadFrom reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +// It consumes the needed bytes from the reader and returns the number of bytes read and an error if any. +// It also returns a channel that will be closed when the validation is done. +// The validation consist of checking that the elements are smaller than the modulus, and +// converting them to montgomery form. +func (vector *Vector) AsyncReadFrom(r io.Reader) (int64, error, chan error) { + chErr := make(chan error, 1) + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + close(chErr) + return int64(read), err, chErr + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + if sliceLen == 0 { + close(chErr) + return n, nil, chErr + } + + bSlice := unsafe.Slice((*byte)(unsafe.Pointer(&(*vector)[0])), sliceLen*Bytes) + read, err := io.ReadFull(r, bSlice) + n += int64(read) + if err != nil { + close(chErr) + return n, err, chErr + } + + go func() { + var cptErrors uint64 + // process the elements in parallel + execute(int(sliceLen), func(start, end int) { + + var z Element + for i := start; i < end; i++ { + // we have to set vector[i] + bstart := i * Bytes + bend := bstart + Bytes + b := bSlice[bstart:bend] + z[0] = binary.BigEndian.Uint64(b[40:48]) + z[1] = binary.BigEndian.Uint64(b[32:40]) + z[2] = binary.BigEndian.Uint64(b[24:32]) + z[3] = binary.BigEndian.Uint64(b[16:24]) + z[4] = binary.BigEndian.Uint64(b[8:16]) + z[5] = binary.BigEndian.Uint64(b[0:8]) + + if !z.smallerThanModulus() { + atomic.AddUint64(&cptErrors, 1) + return + } + z.toMont() + (*vector)[i] = z + } + }) + + if cptErrors > 0 { + chErr <- fmt.Errorf("async read: %d elements failed validation", cptErrors) + } + close(chErr) + }() + return n, nil, chErr +} + +// ReadFrom implements io.ReaderFrom and reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +func (vector *Vector) ReadFrom(r io.Reader) (int64, error) { + + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + return int64(read), err + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + + for i := 0; i < int(sliceLen); i++ { + read, err := io.ReadFull(r, buf[:]) + n += int64(read) + if err != nil { + return n, err + } + (*vector)[i], err = BigEndian.Element(&buf) + if err != nil { + return n, err + } + } + + return n, nil +} + +// String implements fmt.Stringer interface +func (vector Vector) String() string { + var sbb strings.Builder + sbb.WriteByte('[') + for i := 0; i < len(vector); i++ { + sbb.WriteString(vector[i].String()) + if i != len(vector)-1 { + sbb.WriteByte(',') + } + } + sbb.WriteByte(']') + return sbb.String() +} + +// Len is the number of elements in the collection. +func (vector Vector) Len() int { + return len(vector) +} + +// Less reports whether the element with +// index i should sort before the element with index j. +func (vector Vector) Less(i, j int) bool { + return vector[i].Cmp(&vector[j]) == -1 +} + +// Swap swaps the elements with indexes i and j. +func (vector Vector) Swap(i, j int) { + vector[i], vector[j] = vector[j], vector[i] +} + +// TODO @gbotrel make a public package out of that. +// execute executes the work function in parallel. +// this is copy paste from internal/parallel/parallel.go +// as we don't want to generate code importing internal/ +func execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + if nbTasks < 1 { + nbTasks = 1 + } else if nbTasks > 512 { + nbTasks = 512 + } + } + + if nbTasks == 1 { + // no go routines + work(0, nbIterations) + return + } + + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/arith.go new file mode 100644 index 00000000000..7cfd55da199 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/arith.go @@ -0,0 +1,73 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "math/bits" +) + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} +func max(a int, b int) int { + if a > b { + return a + } + return b +} + +func min(a int, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm.go similarity index 80% rename from vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/doc.go rename to vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm.go index 497bd40a972..da061913ba7 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/doc.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm.go @@ -1,3 +1,6 @@ +//go:build !noadx +// +build !noadx + // Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,5 +17,11 @@ // Code generated by consensys/gnark-crypto DO NOT EDIT -// Package mimc provides MiMC hash function using Miyaguchi–Preneel construction. -package mimc +package fr + +import "golang.org/x/sys/cpu" + +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm_noadx.go new file mode 100644 index 00000000000..7f52ffa197b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/asm_noadx.go @@ -0,0 +1,28 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var ( + supportAdx = false + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/doc.go new file mode 100644 index 00000000000..08f1a0ba2ec --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/doc.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package fr contains field arithmetic operations for modulus = 0x12ab65...000001. +// +// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x for the modular multiplication on amd64, see also https://hackmd.io/@gnark/modular_multiplication) +// +// The modulus is hardcoded in all the operations. +// +// Field elements are represented as an array, and assumed to be in Montgomery form in all methods: +// +// type Element [4]uint64 +// +// # Usage +// +// Example API signature: +// +// // Mul z = x * y (mod q) +// func (z *Element) Mul(x, y *Element) *Element +// +// and can be used like so: +// +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus q = +// +// q[base10] = 8444461749428370424248824938781546531375899335154063827935233455917409239041 +// q[base16] = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +package fr diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go new file mode 100644 index 00000000000..07be74489e8 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go @@ -0,0 +1,1620 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "crypto/rand" + "encoding/binary" + "errors" + "io" + "math/big" + "math/bits" + "reflect" + "strconv" + "strings" + + "github.com/bits-and-blooms/bitset" + "github.com/consensys/gnark-crypto/field/hash" + "github.com/consensys/gnark-crypto/field/pool" +) + +// Element represents a field element stored on 4 words (uint64) +// +// Element are assumed to be in Montgomery form in all methods. +// +// Modulus q = +// +// q[base10] = 8444461749428370424248824938781546531375899335154063827935233455917409239041 +// q[base16] = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +type Element [4]uint64 + +const ( + Limbs = 4 // number of 64 bits words needed to represent a Element + Bits = 253 // number of bits needed to represent a Element + Bytes = 32 // number of bytes needed to represent a Element +) + +// Field modulus q +const ( + q0 uint64 = 725501752471715841 + q1 uint64 = 6461107452199829505 + q2 uint64 = 6968279316240510977 + q3 uint64 = 1345280370688173398 +) + +var qElement = Element{ + q0, + q1, + q2, + q3, +} + +var _modulus big.Int // q stored as big.Int + +// Modulus returns q as a big.Int +// +// q[base10] = 8444461749428370424248824938781546531375899335154063827935233455917409239041 +// q[base16] = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 +func Modulus() *big.Int { + return new(big.Int).Set(&_modulus) +} + +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 725501752471715839 + +func init() { + _modulus.SetString("12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001", 16) +} + +// NewElement returns a new Element from a uint64 value +// +// it is equivalent to +// +// var v Element +// v.SetUint64(...) +func NewElement(v uint64) Element { + z := Element{v} + z.Mul(&z, &rSquare) + return z +} + +// SetUint64 sets z to v and returns z +func (z *Element) SetUint64(v uint64) *Element { + // sets z LSB to v (non-Montgomery form) and convert z to Montgomery form + *z = Element{v} + return z.Mul(z, &rSquare) // z.toMont() +} + +// SetInt64 sets z to v and returns z +func (z *Element) SetInt64(v int64) *Element { + + // absolute value of v + m := v >> 63 + z.SetUint64(uint64((v ^ m) - m)) + + if m != 0 { + // v is negative + z.Neg(z) + } + + return z +} + +// Set z = x and returns z +func (z *Element) Set(x *Element) *Element { + z[0] = x[0] + z[1] = x[1] + z[2] = x[2] + z[3] = x[3] + return z +} + +// SetInterface converts provided interface into Element +// returns an error if provided type is not supported +// supported types: +// +// Element +// *Element +// uint64 +// int +// string (see SetString for valid formats) +// *big.Int +// big.Int +// []byte +func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + if i1 == nil { + return nil, errors.New("can't set fr.Element with ") + } + + switch c1 := i1.(type) { + case Element: + return z.Set(&c1), nil + case *Element: + if c1 == nil { + return nil, errors.New("can't set fr.Element with ") + } + return z.Set(c1), nil + case uint8: + return z.SetUint64(uint64(c1)), nil + case uint16: + return z.SetUint64(uint64(c1)), nil + case uint32: + return z.SetUint64(uint64(c1)), nil + case uint: + return z.SetUint64(uint64(c1)), nil + case uint64: + return z.SetUint64(c1), nil + case int8: + return z.SetInt64(int64(c1)), nil + case int16: + return z.SetInt64(int64(c1)), nil + case int32: + return z.SetInt64(int64(c1)), nil + case int64: + return z.SetInt64(c1), nil + case int: + return z.SetInt64(int64(c1)), nil + case string: + return z.SetString(c1) + case *big.Int: + if c1 == nil { + return nil, errors.New("can't set fr.Element with ") + } + return z.SetBigInt(c1), nil + case big.Int: + return z.SetBigInt(&c1), nil + case []byte: + return z.SetBytes(c1), nil + default: + return nil, errors.New("can't set fr.Element from type " + reflect.TypeOf(i1).String()) + } +} + +// SetZero z = 0 +func (z *Element) SetZero() *Element { + z[0] = 0 + z[1] = 0 + z[2] = 0 + z[3] = 0 + return z +} + +// SetOne z = 1 (in Montgomery form) +func (z *Element) SetOne() *Element { + z[0] = 9015221291577245683 + z[1] = 8239323489949974514 + z[2] = 1646089257421115374 + z[3] = 958099254763297437 + return z +} + +// Div z = x*y⁻¹ (mod q) +func (z *Element) Div(x, y *Element) *Element { + var yInv Element + yInv.Inverse(y) + z.Mul(x, &yInv) + return z +} + +// Equal returns z == x; constant-time +func (z *Element) Equal(x *Element) bool { + return z.NotEqual(x) == 0 +} + +// NotEqual returns 0 if and only if z == x; constant-time +func (z *Element) NotEqual(x *Element) uint64 { + return (z[3] ^ x[3]) | (z[2] ^ x[2]) | (z[1] ^ x[1]) | (z[0] ^ x[0]) +} + +// IsZero returns z == 0 +func (z *Element) IsZero() bool { + return (z[3] | z[2] | z[1] | z[0]) == 0 +} + +// IsOne returns z == 1 +func (z *Element) IsOne() bool { + return ((z[3] ^ 958099254763297437) | (z[2] ^ 1646089257421115374) | (z[1] ^ 8239323489949974514) | (z[0] ^ 9015221291577245683)) == 0 +} + +// IsUint64 reports whether z can be represented as an uint64. +func (z *Element) IsUint64() bool { + zz := *z + zz.fromMont() + return zz.FitsOnOneWord() +} + +// Uint64 returns the uint64 representation of x. If x cannot be represented in a uint64, the result is undefined. +func (z *Element) Uint64() uint64 { + return z.Bits()[0] +} + +// FitsOnOneWord reports whether z words (except the least significant word) are 0 +// +// It is the responsibility of the caller to convert from Montgomery to Regular form if needed. +func (z *Element) FitsOnOneWord() bool { + return (z[3] | z[2] | z[1]) == 0 +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *Element) Cmp(x *Element) int { + _z := z.Bits() + _x := x.Bits() + if _z[3] > _x[3] { + return 1 + } else if _z[3] < _x[3] { + return -1 + } + if _z[2] > _x[2] { + return 1 + } else if _z[2] < _x[2] { + return -1 + } + if _z[1] > _x[1] { + return 1 + } else if _z[1] < _x[1] { + return -1 + } + if _z[0] > _x[0] { + return 1 + } else if _z[0] < _x[0] { + return -1 + } + return 0 +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *Element) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + // we check if the element is larger than (q-1) / 2 + // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 + + _z := z.Bits() + + var b uint64 + _, b = bits.Sub64(_z[0], 9586122913090633729, 0) + _, b = bits.Sub64(_z[1], 12453925762954690560, b) + _, b = bits.Sub64(_z[2], 3484139658120255488, b) + _, b = bits.Sub64(_z[3], 672640185344086699, b) + + return b == 0 +} + +// SetRandom sets z to a uniform random value in [0, q). +// +// This might error only if reading from crypto/rand.Reader errors, +// in which case, value of z is undefined. +func (z *Element) SetRandom() (*Element, error) { + // this code is generated for all modulus + // and derived from go/src/crypto/rand/util.go + + // l is number of limbs * 8; the number of bytes needed to reconstruct 4 uint64 + const l = 32 + + // bitLen is the maximum bit length needed to encode a value < q. + const bitLen = 253 + + // k is the maximum byte length needed to encode a value < q. + const k = (bitLen + 7) / 8 + + // b is the number of bits in the most significant byte of q-1. + b := uint(bitLen % 8) + if b == 0 { + b = 8 + } + + var bytes [l]byte + + for { + // note that bytes[k:l] is always 0 + if _, err := io.ReadFull(rand.Reader, bytes[:k]); err != nil { + return nil, err + } + + // Clear unused bits in in the most significant byte to increase probability + // that the candidate is < q. + bytes[k-1] &= uint8(int(1<> 1 + z[0] = z[0]>>1 | z[1]<<63 + z[1] = z[1]>>1 | z[2]<<63 + z[2] = z[2]>>1 | z[3]<<63 + z[3] >>= 1 + +} + +// fromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func (z *Element) fromMont() *Element { + fromMont(z) + return z +} + +// Add z = x + y (mod q) +func (z *Element) Add(x, y *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], _ = bits.Add64(x[3], y[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Double z = x + x (mod q), aka Lsh 1 +func (z *Element) Double(x *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], _ = bits.Add64(x[3], x[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Sub z = x - y (mod q) +func (z *Element) Sub(x, y *Element) *Element { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], q0, 0) + z[1], c = bits.Add64(z[1], q1, c) + z[2], c = bits.Add64(z[2], q2, c) + z[3], _ = bits.Add64(z[3], q3, c) + } + return z +} + +// Neg z = q - x +func (z *Element) Neg(x *Element) *Element { + if x.IsZero() { + z.SetZero() + return z + } + var borrow uint64 + z[0], borrow = bits.Sub64(q0, x[0], 0) + z[1], borrow = bits.Sub64(q1, x[1], borrow) + z[2], borrow = bits.Sub64(q2, x[2], borrow) + z[3], _ = bits.Sub64(q3, x[3], borrow) + return z +} + +// Select is a constant-time conditional move. +// If c=0, z = x0. Else z = x1 +func (z *Element) Select(c int, x0 *Element, x1 *Element) *Element { + cC := uint64((int64(c) | -int64(c)) >> 63) // "canonicized" into: 0 if c=0, -1 otherwise + z[0] = x0[0] ^ cC&(x0[0]^x1[0]) + z[1] = x0[1] ^ cC&(x0[1]^x1[1]) + z[2] = x0[2] ^ cC&(x0[2]^x1[2]) + z[3] = x0[3] ^ cC&(x0[3]^x1[3]) + return z +} + +// _mulGeneric is unoptimized textbook CIOS +// it is a fallback solution on x86 when ADX instruction set is not available +// and is used for testing purposes. +func _mulGeneric(z, x, y *Element) { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + + var t [5]uint64 + var D uint64 + var m, C uint64 + // ----------------------------------- + // First loop + + C, t[0] = bits.Mul64(y[0], x[0]) + C, t[1] = madd1(y[0], x[1], C) + C, t[2] = madd1(y[0], x[2], C) + C, t[3] = madd1(y[0], x[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[1], x[0], t[0]) + C, t[1] = madd2(y[1], x[1], t[1], C) + C, t[2] = madd2(y[1], x[2], t[2], C) + C, t[3] = madd2(y[1], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[2], x[0], t[0]) + C, t[1] = madd2(y[2], x[1], t[1], C) + C, t[2] = madd2(y[2], x[2], t[2], C) + C, t[3] = madd2(y[2], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[3], x[0], t[0]) + C, t[1] = madd2(y[3], x[1], t[1], C) + C, t[2] = madd2(y[3], x[2], t[2], C) + C, t[3] = madd2(y[3], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + + if t[4] != 0 { + // we need to reduce, we have a result on 5 words + var b uint64 + z[0], b = bits.Sub64(t[0], q0, 0) + z[1], b = bits.Sub64(t[1], q1, b) + z[2], b = bits.Sub64(t[2], q2, b) + z[3], _ = bits.Sub64(t[3], q3, b) + return + } + + // copy t into z + z[0] = t[0] + z[1] = t[1] + z[2] = t[2] + z[3] = t[3] + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } +} + +func _fromMontGeneric(z *Element) { + // the following lines implement z = z * 1 + // with a modified CIOS montgomery multiplication + // see Mul for algorithm documentation + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } +} + +func _reduceGeneric(z *Element) { + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } +} + +// BatchInvert returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +func BatchInvert(a []Element) []Element { + res := make([]Element, len(a)) + if len(a) == 0 { + return res + } + + zeroes := bitset.New(uint(len(a))) + accumulator := One() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes.Set(uint(i)) + continue + } + res[i] = accumulator + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes.Test(uint(i)) { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func _butterflyGeneric(a, b *Element) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// BitLen returns the minimum number of bits needed to represent z +// returns 0 if z == 0 +func (z *Element) BitLen() int { + if z[3] != 0 { + return 192 + bits.Len64(z[3]) + } + if z[2] != 0 { + return 128 + bits.Len64(z[2]) + } + if z[1] != 0 { + return 64 + bits.Len64(z[1]) + } + return bits.Len64(z[0]) +} + +// Hash msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func Hash(msg, dst []byte, count int) ([]Element, error) { + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + const Bytes = 1 + (Bits-1)/8 + const L = 16 + Bytes + + lenInBytes := count * L + pseudoRandomBytes, err := hash.ExpandMsgXmd(msg, dst, lenInBytes) + if err != nil { + return nil, err + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + res := make([]Element, count) + for i := 0; i < count; i++ { + vv.SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + res[i].SetBigInt(vv) + } + + // release object into pool + pool.BigInt.Put(vv) + + return res, nil +} + +// Exp z = xᵏ (mod q) +func (z *Element) Exp(x Element, k *big.Int) *Element { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q) == (x⁻¹)ᵏ (mod q) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = pool.BigInt.Get() + defer pool.BigInt.Put(e) + e.Neg(k) + } + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// rSquare where r is the Montgommery constant +// see section 2.3.2 of Tolga Acar's thesis +// https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf +var rSquare = Element{ + 2726216793283724667, + 14712177743343147295, + 12091039717619697043, + 81024008013859129, +} + +// toMont converts z to Montgomery form +// sets and returns z = z * r² +func (z *Element) toMont() *Element { + return z.Mul(z, &rSquare) +} + +// String returns the decimal representation of z as generated by +// z.Text(10). +func (z *Element) String() string { + return z.Text(10) +} + +// toBigInt returns z as a big.Int in Montgomery form +func (z *Element) toBigInt(res *big.Int) *big.Int { + var b [Bytes]byte + binary.BigEndian.PutUint64(b[24:32], z[0]) + binary.BigEndian.PutUint64(b[16:24], z[1]) + binary.BigEndian.PutUint64(b[8:16], z[2]) + binary.BigEndian.PutUint64(b[0:8], z[3]) + + return res.SetBytes(b[:]) +} + +// Text returns the string representation of z in the given base. +// Base must be between 2 and 36, inclusive. The result uses the +// lower-case letters 'a' to 'z' for digit values 10 to 35. +// No prefix (such as "0x") is added to the string. If z is a nil +// pointer it returns "". +// If base == 10 and -z fits in a uint16 prefix "-" is added to the string. +func (z *Element) Text(base int) string { + if base < 2 || base > 36 { + panic("invalid base") + } + if z == nil { + return "" + } + + const maxUint16 = 65535 + if base == 10 { + var zzNeg Element + zzNeg.Neg(z) + zzNeg.fromMont() + if zzNeg.FitsOnOneWord() && zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { + return "-" + strconv.FormatUint(zzNeg[0], base) + } + } + zz := *z + zz.fromMont() + if zz.FitsOnOneWord() { + return strconv.FormatUint(zz[0], base) + } + vv := pool.BigInt.Get() + r := zz.toBigInt(vv).Text(base) + pool.BigInt.Put(vv) + return r +} + +// BigInt sets and return z as a *big.Int +func (z *Element) BigInt(res *big.Int) *big.Int { + _z := *z + _z.fromMont() + return _z.toBigInt(res) +} + +// ToBigIntRegular returns z as a big.Int in regular form +// +// Deprecated: use BigInt(*big.Int) instead +func (z Element) ToBigIntRegular(res *big.Int) *big.Int { + z.fromMont() + return z.toBigInt(res) +} + +// Bits provides access to z by returning its value as a little-endian [4]uint64 array. +// Bits is intended to support implementation of missing low-level Element +// functionality outside this package; it should be avoided otherwise. +func (z *Element) Bits() [4]uint64 { + _z := *z + fromMont(&_z) + return _z +} + +// Bytes returns the value of z as a big-endian byte array +func (z *Element) Bytes() (res [Bytes]byte) { + BigEndian.PutElement(&res, *z) + return +} + +// Marshal returns the value of z as a big-endian byte slice +func (z *Element) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// Unmarshal is an alias for SetBytes, it sets z to the value of e. +func (z *Element) Unmarshal(e []byte) { + z.SetBytes(e) +} + +// SetBytes interprets e as the bytes of a big-endian unsigned integer, +// sets z to that value, and returns z. +func (z *Element) SetBytes(e []byte) *Element { + if len(e) == Bytes { + // fast path + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err == nil { + *z = v + return z + } + } + + // slow path. + // get a big int from our pool + vv := pool.BigInt.Get() + vv.SetBytes(e) + + // set big int + z.SetBigInt(vv) + + // put temporary object back in pool + pool.BigInt.Put(vv) + + return z +} + +// SetBytesCanonical interprets e as the bytes of a big-endian 32-byte integer. +// If e is not a 32-byte slice or encodes a value higher than q, +// SetBytesCanonical returns an error. +func (z *Element) SetBytesCanonical(e []byte) error { + if len(e) != Bytes { + return errors.New("invalid fr.Element encoding") + } + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err != nil { + return err + } + *z = v + return nil +} + +// SetBigInt sets z to v and returns z +func (z *Element) SetBigInt(v *big.Int) *Element { + z.SetZero() + + var zero big.Int + + // fast path + c := v.Cmp(&_modulus) + if c == 0 { + // v == 0 + return z + } else if c != 1 && v.Cmp(&zero) != -1 { + // 0 < v < q + return z.setBigInt(v) + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + // copy input + modular reduction + vv.Mod(v, &_modulus) + + // set big int byte value + z.setBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return z +} + +// setBigInt assumes 0 ⩽ v < q +func (z *Element) setBigInt(v *big.Int) *Element { + vBits := v.Bits() + + if bits.UintSize == 64 { + for i := 0; i < len(vBits); i++ { + z[i] = uint64(vBits[i]) + } + } else { + for i := 0; i < len(vBits); i++ { + if i%2 == 0 { + z[i/2] = uint64(vBits[i]) + } else { + z[i/2] |= uint64(vBits[i]) << 32 + } + } + } + + return z.toMont() +} + +// SetString creates a big.Int with number and calls SetBigInt on z +// +// The number prefix determines the actual base: A prefix of +// ”0b” or ”0B” selects base 2, ”0”, ”0o” or ”0O” selects base 8, +// and ”0x” or ”0X” selects base 16. Otherwise, the selected base is 10 +// and no prefix is accepted. +// +// For base 16, lower and upper case letters are considered the same: +// The letters 'a' to 'f' and 'A' to 'F' represent digit values 10 to 15. +// +// An underscore character ”_” may appear between a base +// prefix and an adjacent digit, and between successive digits; such +// underscores do not change the value of the number. +// Incorrect placement of underscores is reported as a panic if there +// are no other errors. +// +// If the number is invalid this method leaves z unchanged and returns nil, error. +func (z *Element) SetString(number string) (*Element, error) { + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(number, 0); !ok { + return nil, errors.New("Element.SetString failed -> can't parse number into a big.Int " + number) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + + return z, nil +} + +// MarshalJSON returns json encoding of z (z.Text(10)) +// If z == nil, returns null +func (z *Element) MarshalJSON() ([]byte, error) { + if z == nil { + return []byte("null"), nil + } + const maxSafeBound = 15 // we encode it as number if it's small + s := z.Text(10) + if len(s) <= maxSafeBound { + return []byte(s), nil + } + var sbb strings.Builder + sbb.WriteByte('"') + sbb.WriteString(s) + sbb.WriteByte('"') + return []byte(sbb.String()), nil +} + +// UnmarshalJSON accepts numbers and strings as input +// See Element.SetString for valid prefixes (0x, 0b, ...) +func (z *Element) UnmarshalJSON(data []byte) error { + s := string(data) + if len(s) > Bits*3 { + return errors.New("value too large (max = Element.Bits * 3)") + } + + // we accept numbers and strings, remove leading and trailing quotes if any + if len(s) > 0 && s[0] == '"' { + s = s[1:] + } + if len(s) > 0 && s[len(s)-1] == '"' { + s = s[:len(s)-1] + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(s, 0); !ok { + return errors.New("can't parse into a big.Int: " + s) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return nil +} + +// A ByteOrder specifies how to convert byte slices into a Element +type ByteOrder interface { + Element(*[Bytes]byte) (Element, error) + PutElement(*[Bytes]byte, Element) + String() string +} + +// BigEndian is the big-endian implementation of ByteOrder and AppendByteOrder. +var BigEndian bigEndian + +type bigEndian struct{} + +// Element interpret b is a big-endian 32-byte slice. +// If b encodes a value higher than q, Element returns error. +func (bigEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.BigEndian.Uint64((*b)[24:32]) + z[1] = binary.BigEndian.Uint64((*b)[16:24]) + z[2] = binary.BigEndian.Uint64((*b)[8:16]) + z[3] = binary.BigEndian.Uint64((*b)[0:8]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fr.Element encoding") + } + + z.toMont() + return z, nil +} + +func (bigEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.BigEndian.PutUint64((*b)[24:32], e[0]) + binary.BigEndian.PutUint64((*b)[16:24], e[1]) + binary.BigEndian.PutUint64((*b)[8:16], e[2]) + binary.BigEndian.PutUint64((*b)[0:8], e[3]) +} + +func (bigEndian) String() string { return "BigEndian" } + +// LittleEndian is the little-endian implementation of ByteOrder and AppendByteOrder. +var LittleEndian littleEndian + +type littleEndian struct{} + +func (littleEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.LittleEndian.Uint64((*b)[0:8]) + z[1] = binary.LittleEndian.Uint64((*b)[8:16]) + z[2] = binary.LittleEndian.Uint64((*b)[16:24]) + z[3] = binary.LittleEndian.Uint64((*b)[24:32]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fr.Element encoding") + } + + z.toMont() + return z, nil +} + +func (littleEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.LittleEndian.PutUint64((*b)[0:8], e[0]) + binary.LittleEndian.PutUint64((*b)[8:16], e[1]) + binary.LittleEndian.PutUint64((*b)[16:24], e[2]) + binary.LittleEndian.PutUint64((*b)[24:32], e[3]) +} + +func (littleEndian) String() string { return "LittleEndian" } + +// Legendre returns the Legendre symbol of z (either +1, -1, or 0.) +func (z *Element) Legendre() int { + var l Element + // z^((q-1)/2) + l.expByLegendreExp(*z) + + if l.IsZero() { + return 0 + } + + // if l == 1 + if l.IsOne() { + return 1 + } + return -1 +} + +// Sqrt z = √x (mod q) +// if the square root doesn't exist (x is not a square mod q) +// Sqrt leaves z unchanged and returns nil +func (z *Element) Sqrt(x *Element) *Element { + // q ≡ 1 (mod 4) + // see modSqrtTonelliShanks in math/big/int.go + // using https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + + var y, b, t, w Element + // w = x^((s-1)/2)) + w.expBySqrtExp(*x) + + // y = x^((s+1)/2)) = w * x + y.Mul(x, &w) + + // b = xˢ = w * w * x = y * x + b.Mul(&w, &y) + + // g = nonResidue ^ s + var g = Element{ + 4340692304772210610, + 11102725085307959083, + 15540458298643990566, + 944526744080888988, + } + r := uint64(47) + + // compute legendre symbol + // t = x^((q-1)/2) = r-1 squaring of xˢ + t = b + for i := uint64(0); i < r-1; i++ { + t.Square(&t) + } + if t.IsZero() { + return z.SetZero() + } + if !t.IsOne() { + // t != 1, we don't have a square root + return nil + } + for { + var m uint64 + t = b + + // for t != 1 + for !t.IsOne() { + t.Square(&t) + m++ + } + + if m == 0 { + return z.Set(&y) + } + // t = g^(2^(r-m-1)) (mod q) + ge := int(r - m - 1) + t = g + for ge > 0 { + t.Square(&t) + ge-- + } + + g.Square(&t) + y.Mul(&y, &t) + b.Mul(&b, &g) + r = m + } +} + +const ( + k = 32 // word size / 2 + signBitSelector = uint64(1) << 63 + approxLowBitsN = k - 1 + approxHighBitsN = k + 1 +) + +const ( + inversionCorrectionFactorWord0 = 10532255328610800637 + inversionCorrectionFactorWord1 = 12368705355905441295 + inversionCorrectionFactorWord2 = 4360254653162267807 + inversionCorrectionFactorWord3 = 835375988631323795 + invIterationsN = 18 +) + +// Inverse z = x⁻¹ (mod q) +// +// if x == 0, sets and returns z = x +func (z *Element) Inverse(x *Element) *Element { + // Implements "Optimized Binary GCD for Modular Inversion" + // https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf + + a := *x + b := Element{ + q0, + q1, + q2, + q3, + } // b := q + + u := Element{1} + + // Update factors: we get [u; v] ← [f₀ g₀; f₁ g₁] [u; v] + // cᵢ = fᵢ + 2³¹ - 1 + 2³² * (gᵢ + 2³¹ - 1) + var c0, c1 int64 + + // Saved update factors to reduce the number of field multiplications + var pf0, pf1, pg0, pg1 int64 + + var i uint + + var v, s Element + + // Since u,v are updated every other iteration, we must make sure we terminate after evenly many iterations + // This also lets us get away with half as many updates to u,v + // To make this constant-time-ish, replace the condition with i < invIterationsN + for i = 0; i&1 == 1 || !a.IsZero(); i++ { + n := max(a.BitLen(), b.BitLen()) + aApprox, bApprox := approximate(&a, n), approximate(&b, n) + + // f₀, g₀, f₁, g₁ = 1, 0, 0, 1 + c0, c1 = updateFactorIdentityMatrixRow0, updateFactorIdentityMatrixRow1 + + for j := 0; j < approxLowBitsN; j++ { + + // -2ʲ < f₀, f₁ ≤ 2ʲ + // |f₀| + |f₁| < 2ʲ⁺¹ + + if aApprox&1 == 0 { + aApprox /= 2 + } else { + s, borrow := bits.Sub64(aApprox, bApprox, 0) + if borrow == 1 { + s = bApprox - aApprox + bApprox = aApprox + c0, c1 = c1, c0 + // invariants unchanged + } + + aApprox = s / 2 + c0 = c0 - c1 + + // Now |f₀| < 2ʲ⁺¹ ≤ 2ʲ⁺¹ (only the weaker inequality is needed, strictly speaking) + // Started with f₀ > -2ʲ and f₁ ≤ 2ʲ, so f₀ - f₁ > -2ʲ⁺¹ + // Invariants unchanged for f₁ + } + + c1 *= 2 + // -2ʲ⁺¹ < f₁ ≤ 2ʲ⁺¹ + // So now |f₀| + |f₁| < 2ʲ⁺² + } + + s = a + + var g0 int64 + // from this point on c0 aliases for f0 + c0, g0 = updateFactorsDecompose(c0) + aHi := a.linearCombNonModular(&s, c0, &b, g0) + if aHi&signBitSelector != 0 { + // if aHi < 0 + c0, g0 = -c0, -g0 + aHi = negL(&a, aHi) + } + // right-shift a by k-1 bits + a[0] = (a[0] >> approxLowBitsN) | ((a[1]) << approxHighBitsN) + a[1] = (a[1] >> approxLowBitsN) | ((a[2]) << approxHighBitsN) + a[2] = (a[2] >> approxLowBitsN) | ((a[3]) << approxHighBitsN) + a[3] = (a[3] >> approxLowBitsN) | (aHi << approxHighBitsN) + + var f1 int64 + // from this point on c1 aliases for g0 + f1, c1 = updateFactorsDecompose(c1) + bHi := b.linearCombNonModular(&s, f1, &b, c1) + if bHi&signBitSelector != 0 { + // if bHi < 0 + f1, c1 = -f1, -c1 + bHi = negL(&b, bHi) + } + // right-shift b by k-1 bits + b[0] = (b[0] >> approxLowBitsN) | ((b[1]) << approxHighBitsN) + b[1] = (b[1] >> approxLowBitsN) | ((b[2]) << approxHighBitsN) + b[2] = (b[2] >> approxLowBitsN) | ((b[3]) << approxHighBitsN) + b[3] = (b[3] >> approxLowBitsN) | (bHi << approxHighBitsN) + + if i&1 == 1 { + // Combine current update factors with previously stored ones + // [F₀, G₀; F₁, G₁] ← [f₀, g₀; f₁, g₁] [pf₀, pg₀; pf₁, pg₁], with capital letters denoting new combined values + // We get |F₀| = | f₀pf₀ + g₀pf₁ | ≤ |f₀pf₀| + |g₀pf₁| = |f₀| |pf₀| + |g₀| |pf₁| ≤ 2ᵏ⁻¹|pf₀| + 2ᵏ⁻¹|pf₁| + // = 2ᵏ⁻¹ (|pf₀| + |pf₁|) < 2ᵏ⁻¹ 2ᵏ = 2²ᵏ⁻¹ + // So |F₀| < 2²ᵏ⁻¹ meaning it fits in a 2k-bit signed register + + // c₀ aliases f₀, c₁ aliases g₁ + c0, g0, f1, c1 = c0*pf0+g0*pf1, + c0*pg0+g0*pg1, + f1*pf0+c1*pf1, + f1*pg0+c1*pg1 + + s = u + + // 0 ≤ u, v < 2²⁵⁵ + // |F₀|, |G₀| < 2⁶³ + u.linearComb(&u, c0, &v, g0) + // |F₁|, |G₁| < 2⁶³ + v.linearComb(&s, f1, &v, c1) + + } else { + // Save update factors + pf0, pg0, pf1, pg1 = c0, g0, f1, c1 + } + } + + // For every iteration that we miss, v is not being multiplied by 2ᵏ⁻² + const pSq uint64 = 1 << (2 * (k - 1)) + a = Element{pSq} + // If the function is constant-time ish, this loop will not run (no need to take it out explicitly) + for ; i < invIterationsN; i += 2 { + // could optimize further with mul by word routine or by pre-computing a table since with k=26, + // we would multiply by pSq up to 13times; + // on x86, the assembly routine outperforms generic code for mul by word + // on arm64, we may loose up to ~5% for 6 limbs + v.Mul(&v, &a) + } + + u.Set(x) // for correctness check + + z.Mul(&v, &Element{ + inversionCorrectionFactorWord0, + inversionCorrectionFactorWord1, + inversionCorrectionFactorWord2, + inversionCorrectionFactorWord3, + }) + + // correctness check + v.Mul(&u, z) + if !v.IsOne() && !u.IsZero() { + return z.inverseExp(u) + } + + return z +} + +// inverseExp computes z = x⁻¹ (mod q) = x**(q-2) (mod q) +func (z *Element) inverseExp(x Element) *Element { + // e == q-2 + e := Modulus() + e.Sub(e, big.NewInt(2)) + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// approximate a big number x into a single 64 bit word using its uppermost and lowermost bits +// if x fits in a word as is, no approximation necessary +func approximate(x *Element, nBits int) uint64 { + + if nBits <= 64 { + return x[0] + } + + const mask = (uint64(1) << (k - 1)) - 1 // k-1 ones + lo := mask & x[0] + + hiWordIndex := (nBits - 1) / 64 + + hiWordBitsAvailable := nBits - hiWordIndex*64 + hiWordBitsUsed := min(hiWordBitsAvailable, approxHighBitsN) + + mask_ := uint64(^((1 << (hiWordBitsAvailable - hiWordBitsUsed)) - 1)) + hi := (x[hiWordIndex] & mask_) << (64 - hiWordBitsAvailable) + + mask_ = ^(1<<(approxLowBitsN+hiWordBitsUsed) - 1) + mid := (mask_ & x[hiWordIndex-1]) >> hiWordBitsUsed + + return lo | mid | hi +} + +// linearComb z = xC * x + yC * y; +// 0 ≤ x, y < 2²⁵³ +// |xC|, |yC| < 2⁶³ +func (z *Element) linearComb(x *Element, xC int64, y *Element, yC int64) { + // | (hi, z) | < 2 * 2⁶³ * 2²⁵³ = 2³¹⁷ + // therefore | hi | < 2⁶¹ ≤ 2⁶³ + hi := z.linearCombNonModular(x, xC, y, yC) + z.montReduceSigned(z, hi) +} + +// montReduceSigned z = (xHi * r + x) * r⁻¹ using the SOS algorithm +// Requires |xHi| < 2⁶³. Most significant bit of xHi is the sign bit. +func (z *Element) montReduceSigned(x *Element, xHi uint64) { + const signBitRemover = ^signBitSelector + mustNeg := xHi&signBitSelector != 0 + // the SOS implementation requires that most significant bit is 0 + // Let X be xHi*r + x + // If X is negative we would have initially stored it as 2⁶⁴ r + X (à la 2's complement) + xHi &= signBitRemover + // with this a negative X is now represented as 2⁶³ r + X + + var t [2*Limbs - 1]uint64 + var C uint64 + + m := x[0] * qInvNeg + + C = madd0(m, q0, x[0]) + C, t[1] = madd2(m, q1, x[1], C) + C, t[2] = madd2(m, q2, x[2], C) + C, t[3] = madd2(m, q3, x[3], C) + + // m * qElement[3] ≤ (2⁶⁴ - 1) * (2⁶³ - 1) = 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + // x[3] + C ≤ 2*(2⁶⁴ - 1) = 2⁶⁵ - 2 + // On LHS, (C, t[3]) ≤ 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + 2⁶⁵ - 2 = 2¹²⁷ + 2⁶³ - 1 + // So on LHS, C ≤ 2⁶³ + t[4] = xHi + C + // xHi + C < 2⁶³ + 2⁶³ = 2⁶⁴ + + // + { + const i = 1 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + + t[i+Limbs] += C + } + { + const i = 2 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + + t[i+Limbs] += C + } + { + const i = 3 + m := t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, z[0] = madd2(m, q1, t[i+1], C) + C, z[1] = madd2(m, q2, t[i+2], C) + z[3], z[2] = madd2(m, q3, t[i+3], C) + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + // + + if mustNeg { + // We have computed ( 2⁶³ r + X ) r⁻¹ = 2⁶³ + X r⁻¹ instead + var b uint64 + z[0], b = bits.Sub64(z[0], signBitSelector, 0) + z[1], b = bits.Sub64(z[1], 0, b) + z[2], b = bits.Sub64(z[2], 0, b) + z[3], b = bits.Sub64(z[3], 0, b) + + // Occurs iff x == 0 && xHi < 0, i.e. X = rX' for -2⁶³ ≤ X' < 0 + + if b != 0 { + // z[3] = -1 + // negative: add q + const neg1 = 0xFFFFFFFFFFFFFFFF + + var carry uint64 + + z[0], carry = bits.Add64(z[0], q0, 0) + z[1], carry = bits.Add64(z[1], q1, carry) + z[2], carry = bits.Add64(z[2], q2, carry) + z[3], _ = bits.Add64(neg1, q3, carry) + } + } +} + +const ( + updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) + updateFactorIdentityMatrixRow0 = 1 + updateFactorIdentityMatrixRow1 = 1 << 32 +) + +func updateFactorsDecompose(c int64) (int64, int64) { + c += updateFactorsConversionBias + const low32BitsFilter int64 = 0xFFFFFFFF + f := c&low32BitsFilter - 0x7FFFFFFF + g := c>>32&low32BitsFilter - 0x7FFFFFFF + return f, g +} + +// negL negates in place [x | xHi] and return the new most significant word xHi +func negL(x *Element, xHi uint64) uint64 { + var b uint64 + + x[0], b = bits.Sub64(0, x[0], 0) + x[1], b = bits.Sub64(0, x[1], b) + x[2], b = bits.Sub64(0, x[2], b) + x[3], b = bits.Sub64(0, x[3], b) + xHi, _ = bits.Sub64(0, xHi, b) + + return xHi +} + +// mulWNonModular multiplies by one word in non-montgomery, without reducing +func (z *Element) mulWNonModular(x *Element, y int64) uint64 { + + // w := abs(y) + m := y >> 63 + w := uint64((y ^ m) - m) + + var c uint64 + c, z[0] = bits.Mul64(x[0], w) + c, z[1] = madd1(x[1], w, c) + c, z[2] = madd1(x[2], w, c) + c, z[3] = madd1(x[3], w, c) + + if y < 0 { + c = negL(z, c) + } + + return c +} + +// linearCombNonModular computes a linear combination without modular reduction +func (z *Element) linearCombNonModular(x *Element, xC int64, y *Element, yC int64) uint64 { + var yTimes Element + + yHi := yTimes.mulWNonModular(y, yC) + xHi := z.mulWNonModular(x, xC) + + var carry uint64 + z[0], carry = bits.Add64(z[0], yTimes[0], 0) + z[1], carry = bits.Add64(z[1], yTimes[1], carry) + z[2], carry = bits.Add64(z[2], yTimes[2], carry) + z[3], carry = bits.Add64(z[3], yTimes[3], carry) + + yHi, _ = bits.Add64(xHi, yHi, carry) + + return yHi +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_exp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_exp.go new file mode 100644 index 00000000000..654ea55faa3 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_exp.go @@ -0,0 +1,623 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +// expBySqrtExp is equivalent to z.Exp(x, 12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expBySqrtExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _101 = _10 + _11 + // _1000 = _11 + _101 + // _1011 = _11 + _1000 + // _10000 = _101 + _1011 + // _10001 = 1 + _10000 + // _10110 = _101 + _10001 + // _100000 = 2*_10000 + // _101011 = _1011 + _100000 + // _101101 = _10 + _101011 + // _1011010 = 2*_101101 + // _1011011 = 1 + _1011010 + // _1111011 = _100000 + _1011011 + // _10000101 = _101011 + _1011010 + // _10001011 = _10000 + _1111011 + // _10100101 = _100000 + _10000101 + // _10101011 = _100000 + _10001011 + // _11000001 = _10110 + _10101011 + // _11000011 = _10 + _11000001 + // _11010001 = _10000 + _11000001 + // _11010011 = _10 + _11010001 + // _11010101 = _10 + _11010011 + // _11100101 = _10000 + _11010101 + // _11101101 = _1000 + _11100101 + // i45 = ((_10000101 + _10100101) << 7 + _1011011) << 10 + _10101011 + // i74 = ((i45 << 8 + _11010011) << 9 + _10001011) << 10 + // i94 = ((_10100101 + i74) << 7 + _101011) << 10 + _11000001 + // i123 = ((i94 << 9 + _11010001) << 10 + _11010001) << 8 + // i142 = ((_11100101 + i123) << 8 + _11000011) << 8 + _1111011 + // i181 = ((i142 << 17 + _101011) << 10 + _11010101) << 10 + // i195 = ((_11101101 + i181) << 8 + _11101101 + _10000) << 3 + // return ((_101 + i195) << 35 + _10000101) << 9 + _10001 + // + // Operations: 199 squares 43 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + t12 = new(Element) + t13 = new(Element) + t14 = new(Element) + t15 = new(Element) + t16 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16 Element + // Step 1: t4 = x^0x2 + t4.Square(&x) + + // Step 2: z = x^0x3 + z.Mul(&x, t4) + + // Step 3: t1 = x^0x5 + t1.Mul(t4, z) + + // Step 4: t3 = x^0x8 + t3.Mul(z, t1) + + // Step 5: t0 = x^0xb + t0.Mul(z, t3) + + // Step 6: t2 = x^0x10 + t2.Mul(t1, t0) + + // Step 7: z = x^0x11 + z.Mul(&x, t2) + + // Step 8: t7 = x^0x16 + t7.Mul(t1, z) + + // Step 9: t8 = x^0x20 + t8.Square(t2) + + // Step 10: t5 = x^0x2b + t5.Mul(t0, t8) + + // Step 11: t0 = x^0x2d + t0.Mul(t4, t5) + + // Step 12: t0 = x^0x5a + t0.Square(t0) + + // Step 13: t15 = x^0x5b + t15.Mul(&x, t0) + + // Step 14: t6 = x^0x7b + t6.Mul(t8, t15) + + // Step 15: t0 = x^0x85 + t0.Mul(t5, t0) + + // Step 16: t12 = x^0x8b + t12.Mul(t2, t6) + + // Step 17: t11 = x^0xa5 + t11.Mul(t8, t0) + + // Step 18: t14 = x^0xab + t14.Mul(t8, t12) + + // Step 19: t10 = x^0xc1 + t10.Mul(t7, t14) + + // Step 20: t7 = x^0xc3 + t7.Mul(t4, t10) + + // Step 21: t9 = x^0xd1 + t9.Mul(t2, t10) + + // Step 22: t13 = x^0xd3 + t13.Mul(t4, t9) + + // Step 23: t4 = x^0xd5 + t4.Mul(t4, t13) + + // Step 24: t8 = x^0xe5 + t8.Mul(t2, t4) + + // Step 25: t3 = x^0xed + t3.Mul(t3, t8) + + // Step 26: t16 = x^0x12a + t16.Mul(t0, t11) + + // Step 33: t16 = x^0x9500 + for s := 0; s < 7; s++ { + t16.Square(t16) + } + + // Step 34: t15 = x^0x955b + t15.Mul(t15, t16) + + // Step 44: t15 = x^0x2556c00 + for s := 0; s < 10; s++ { + t15.Square(t15) + } + + // Step 45: t14 = x^0x2556cab + t14.Mul(t14, t15) + + // Step 53: t14 = x^0x2556cab00 + for s := 0; s < 8; s++ { + t14.Square(t14) + } + + // Step 54: t13 = x^0x2556cabd3 + t13.Mul(t13, t14) + + // Step 63: t13 = x^0x4aad957a600 + for s := 0; s < 9; s++ { + t13.Square(t13) + } + + // Step 64: t12 = x^0x4aad957a68b + t12.Mul(t12, t13) + + // Step 74: t12 = x^0x12ab655e9a2c00 + for s := 0; s < 10; s++ { + t12.Square(t12) + } + + // Step 75: t11 = x^0x12ab655e9a2ca5 + t11.Mul(t11, t12) + + // Step 82: t11 = x^0x955b2af4d165280 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 83: t11 = x^0x955b2af4d1652ab + t11.Mul(t5, t11) + + // Step 93: t11 = x^0x2556cabd34594aac00 + for s := 0; s < 10; s++ { + t11.Square(t11) + } + + // Step 94: t10 = x^0x2556cabd34594aacc1 + t10.Mul(t10, t11) + + // Step 103: t10 = x^0x4aad957a68b295598200 + for s := 0; s < 9; s++ { + t10.Square(t10) + } + + // Step 104: t10 = x^0x4aad957a68b2955982d1 + t10.Mul(t9, t10) + + // Step 114: t10 = x^0x12ab655e9a2ca55660b4400 + for s := 0; s < 10; s++ { + t10.Square(t10) + } + + // Step 115: t9 = x^0x12ab655e9a2ca55660b44d1 + t9.Mul(t9, t10) + + // Step 123: t9 = x^0x12ab655e9a2ca55660b44d100 + for s := 0; s < 8; s++ { + t9.Square(t9) + } + + // Step 124: t8 = x^0x12ab655e9a2ca55660b44d1e5 + t8.Mul(t8, t9) + + // Step 132: t8 = x^0x12ab655e9a2ca55660b44d1e500 + for s := 0; s < 8; s++ { + t8.Square(t8) + } + + // Step 133: t7 = x^0x12ab655e9a2ca55660b44d1e5c3 + t7.Mul(t7, t8) + + // Step 141: t7 = x^0x12ab655e9a2ca55660b44d1e5c300 + for s := 0; s < 8; s++ { + t7.Square(t7) + } + + // Step 142: t6 = x^0x12ab655e9a2ca55660b44d1e5c37b + t6.Mul(t6, t7) + + // Step 159: t6 = x^0x2556cabd34594aacc1689a3cb86f60000 + for s := 0; s < 17; s++ { + t6.Square(t6) + } + + // Step 160: t5 = x^0x2556cabd34594aacc1689a3cb86f6002b + t5.Mul(t5, t6) + + // Step 170: t5 = x^0x955b2af4d1652ab305a268f2e1bd800ac00 + for s := 0; s < 10; s++ { + t5.Square(t5) + } + + // Step 171: t4 = x^0x955b2af4d1652ab305a268f2e1bd800acd5 + t4.Mul(t4, t5) + + // Step 181: t4 = x^0x2556cabd34594aacc1689a3cb86f6002b35400 + for s := 0; s < 10; s++ { + t4.Square(t4) + } + + // Step 182: t4 = x^0x2556cabd34594aacc1689a3cb86f6002b354ed + t4.Mul(t3, t4) + + // Step 190: t4 = x^0x2556cabd34594aacc1689a3cb86f6002b354ed00 + for s := 0; s < 8; s++ { + t4.Square(t4) + } + + // Step 191: t3 = x^0x2556cabd34594aacc1689a3cb86f6002b354eded + t3.Mul(t3, t4) + + // Step 192: t2 = x^0x2556cabd34594aacc1689a3cb86f6002b354edfd + t2.Mul(t2, t3) + + // Step 195: t2 = x^0x12ab655e9a2ca55660b44d1e5c37b00159aa76fe8 + for s := 0; s < 3; s++ { + t2.Square(t2) + } + + // Step 196: t1 = x^0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed + t1.Mul(t1, t2) + + // Step 231: t1 = x^0x955b2af4d1652ab305a268f2e1bd800acd53b7f6800000000 + for s := 0; s < 35; s++ { + t1.Square(t1) + } + + // Step 232: t0 = x^0x955b2af4d1652ab305a268f2e1bd800acd53b7f6800000085 + t0.Mul(t0, t1) + + // Step 241: t0 = x^0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a00 + for s := 0; s < 9; s++ { + t0.Square(t0) + } + + // Step 242: z = x^0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11 + z.Mul(z, t0) + + return z +} + +// expByLegendreExp is equivalent to z.Exp(x, 955b2af4d1652ab305a268f2e1bd800acd53b7f680000008508c00000000000) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expByLegendreExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _101 = _10 + _11 + // _110 = 1 + _101 + // _1000 = _10 + _110 + // _10000 = 2*_1000 + // _10110 = _110 + _10000 + // _100000 = 2*_10000 + // _100011 = _11 + _100000 + // _101011 = _1000 + _100011 + // _101101 = _10 + _101011 + // _1011010 = 2*_101101 + // _1011011 = 1 + _1011010 + // _1111011 = _100000 + _1011011 + // _10000101 = _101011 + _1011010 + // _10001011 = _110 + _10000101 + // _10100101 = _100000 + _10000101 + // _10101011 = _110 + _10100101 + // _11000001 = _10110 + _10101011 + // _11000011 = _10 + _11000001 + // _11010001 = _10000 + _11000001 + // _11010011 = _10 + _11010001 + // _11010101 = _10 + _11010011 + // _11100101 = _10000 + _11010101 + // _11101101 = _1000 + _11100101 + // i45 = ((_10000101 + _10100101) << 7 + _1011011) << 10 + _10101011 + // i74 = ((i45 << 8 + _11010011) << 9 + _10001011) << 10 + // i94 = ((_10100101 + i74) << 7 + _101011) << 10 + _11000001 + // i123 = ((i94 << 9 + _11010001) << 10 + _11010001) << 8 + // i142 = ((_11100101 + i123) << 8 + _11000011) << 8 + _1111011 + // i181 = ((i142 << 17 + _101011) << 10 + _11010101) << 10 + // i195 = ((_11101101 + i181) << 8 + _11101101 + _10000) << 3 + // i243 = ((_101 + i195) << 35 + _10000101) << 10 + _100011 + // return i243 << 46 + // + // Operations: 247 squares 42 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + t12 = new(Element) + t13 = new(Element) + t14 = new(Element) + t15 = new(Element) + t16 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16 Element + // Step 1: t4 = x^0x2 + t4.Square(&x) + + // Step 2: z = x^0x3 + z.Mul(&x, t4) + + // Step 3: t1 = x^0x5 + t1.Mul(t4, z) + + // Step 4: t8 = x^0x6 + t8.Mul(&x, t1) + + // Step 5: t3 = x^0x8 + t3.Mul(t4, t8) + + // Step 6: t2 = x^0x10 + t2.Square(t3) + + // Step 7: t7 = x^0x16 + t7.Mul(t8, t2) + + // Step 8: t9 = x^0x20 + t9.Square(t2) + + // Step 9: z = x^0x23 + z.Mul(z, t9) + + // Step 10: t5 = x^0x2b + t5.Mul(t3, z) + + // Step 11: t0 = x^0x2d + t0.Mul(t4, t5) + + // Step 12: t0 = x^0x5a + t0.Square(t0) + + // Step 13: t15 = x^0x5b + t15.Mul(&x, t0) + + // Step 14: t6 = x^0x7b + t6.Mul(t9, t15) + + // Step 15: t0 = x^0x85 + t0.Mul(t5, t0) + + // Step 16: t12 = x^0x8b + t12.Mul(t8, t0) + + // Step 17: t11 = x^0xa5 + t11.Mul(t9, t0) + + // Step 18: t14 = x^0xab + t14.Mul(t8, t11) + + // Step 19: t10 = x^0xc1 + t10.Mul(t7, t14) + + // Step 20: t7 = x^0xc3 + t7.Mul(t4, t10) + + // Step 21: t9 = x^0xd1 + t9.Mul(t2, t10) + + // Step 22: t13 = x^0xd3 + t13.Mul(t4, t9) + + // Step 23: t4 = x^0xd5 + t4.Mul(t4, t13) + + // Step 24: t8 = x^0xe5 + t8.Mul(t2, t4) + + // Step 25: t3 = x^0xed + t3.Mul(t3, t8) + + // Step 26: t16 = x^0x12a + t16.Mul(t0, t11) + + // Step 33: t16 = x^0x9500 + for s := 0; s < 7; s++ { + t16.Square(t16) + } + + // Step 34: t15 = x^0x955b + t15.Mul(t15, t16) + + // Step 44: t15 = x^0x2556c00 + for s := 0; s < 10; s++ { + t15.Square(t15) + } + + // Step 45: t14 = x^0x2556cab + t14.Mul(t14, t15) + + // Step 53: t14 = x^0x2556cab00 + for s := 0; s < 8; s++ { + t14.Square(t14) + } + + // Step 54: t13 = x^0x2556cabd3 + t13.Mul(t13, t14) + + // Step 63: t13 = x^0x4aad957a600 + for s := 0; s < 9; s++ { + t13.Square(t13) + } + + // Step 64: t12 = x^0x4aad957a68b + t12.Mul(t12, t13) + + // Step 74: t12 = x^0x12ab655e9a2c00 + for s := 0; s < 10; s++ { + t12.Square(t12) + } + + // Step 75: t11 = x^0x12ab655e9a2ca5 + t11.Mul(t11, t12) + + // Step 82: t11 = x^0x955b2af4d165280 + for s := 0; s < 7; s++ { + t11.Square(t11) + } + + // Step 83: t11 = x^0x955b2af4d1652ab + t11.Mul(t5, t11) + + // Step 93: t11 = x^0x2556cabd34594aac00 + for s := 0; s < 10; s++ { + t11.Square(t11) + } + + // Step 94: t10 = x^0x2556cabd34594aacc1 + t10.Mul(t10, t11) + + // Step 103: t10 = x^0x4aad957a68b295598200 + for s := 0; s < 9; s++ { + t10.Square(t10) + } + + // Step 104: t10 = x^0x4aad957a68b2955982d1 + t10.Mul(t9, t10) + + // Step 114: t10 = x^0x12ab655e9a2ca55660b4400 + for s := 0; s < 10; s++ { + t10.Square(t10) + } + + // Step 115: t9 = x^0x12ab655e9a2ca55660b44d1 + t9.Mul(t9, t10) + + // Step 123: t9 = x^0x12ab655e9a2ca55660b44d100 + for s := 0; s < 8; s++ { + t9.Square(t9) + } + + // Step 124: t8 = x^0x12ab655e9a2ca55660b44d1e5 + t8.Mul(t8, t9) + + // Step 132: t8 = x^0x12ab655e9a2ca55660b44d1e500 + for s := 0; s < 8; s++ { + t8.Square(t8) + } + + // Step 133: t7 = x^0x12ab655e9a2ca55660b44d1e5c3 + t7.Mul(t7, t8) + + // Step 141: t7 = x^0x12ab655e9a2ca55660b44d1e5c300 + for s := 0; s < 8; s++ { + t7.Square(t7) + } + + // Step 142: t6 = x^0x12ab655e9a2ca55660b44d1e5c37b + t6.Mul(t6, t7) + + // Step 159: t6 = x^0x2556cabd34594aacc1689a3cb86f60000 + for s := 0; s < 17; s++ { + t6.Square(t6) + } + + // Step 160: t5 = x^0x2556cabd34594aacc1689a3cb86f6002b + t5.Mul(t5, t6) + + // Step 170: t5 = x^0x955b2af4d1652ab305a268f2e1bd800ac00 + for s := 0; s < 10; s++ { + t5.Square(t5) + } + + // Step 171: t4 = x^0x955b2af4d1652ab305a268f2e1bd800acd5 + t4.Mul(t4, t5) + + // Step 181: t4 = x^0x2556cabd34594aacc1689a3cb86f6002b35400 + for s := 0; s < 10; s++ { + t4.Square(t4) + } + + // Step 182: t4 = x^0x2556cabd34594aacc1689a3cb86f6002b354ed + t4.Mul(t3, t4) + + // Step 190: t4 = x^0x2556cabd34594aacc1689a3cb86f6002b354ed00 + for s := 0; s < 8; s++ { + t4.Square(t4) + } + + // Step 191: t3 = x^0x2556cabd34594aacc1689a3cb86f6002b354eded + t3.Mul(t3, t4) + + // Step 192: t2 = x^0x2556cabd34594aacc1689a3cb86f6002b354edfd + t2.Mul(t2, t3) + + // Step 195: t2 = x^0x12ab655e9a2ca55660b44d1e5c37b00159aa76fe8 + for s := 0; s < 3; s++ { + t2.Square(t2) + } + + // Step 196: t1 = x^0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed + t1.Mul(t1, t2) + + // Step 231: t1 = x^0x955b2af4d1652ab305a268f2e1bd800acd53b7f6800000000 + for s := 0; s < 35; s++ { + t1.Square(t1) + } + + // Step 232: t0 = x^0x955b2af4d1652ab305a268f2e1bd800acd53b7f6800000085 + t0.Mul(t0, t1) + + // Step 242: t0 = x^0x2556cabd34594aacc1689a3cb86f6002b354edfda00000021400 + for s := 0; s < 10; s++ { + t0.Square(t0) + } + + // Step 243: z = x^0x2556cabd34594aacc1689a3cb86f6002b354edfda00000021423 + z.Mul(z, t0) + + // Step 289: z = x^0x955b2af4d1652ab305a268f2e1bd800acd53b7f680000008508c00000000000 + for s := 0; s < 46; s++ { + z.Square(z) + } + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_mul_adx_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_amd64.s similarity index 92% rename from vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_mul_adx_amd64.s rename to vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_amd64.s index 65c040e36b6..dc601e91e38 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_mul_adx_amd64.s +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_mul_amd64.s @@ -1,4 +1,4 @@ -// +build amd64_adx +// +build !purego // Copyright 2020 ConsenSys Software Inc. // @@ -18,14 +18,14 @@ #include "funcdata.h" // modulus q -DATA q<>+0(SB)/8, $0x3c208c16d87cfd47 -DATA q<>+8(SB)/8, $0x97816a916871ca8d -DATA q<>+16(SB)/8, $0xb85045b68181585d -DATA q<>+24(SB)/8, $0x30644e72e131a029 +DATA q<>+0(SB)/8, $0x0a11800000000001 +DATA q<>+8(SB)/8, $0x59aa76fed0000001 +DATA q<>+16(SB)/8, $0x60b44d1e5c37b001 +DATA q<>+24(SB)/8, $0x12ab655e9a2ca556 GLOBL q<>(SB), (RODATA+NOPTR), $32 // qInv0 q'[0] -DATA qInv0<>(SB)/8, $0x87d20782e4866389 +DATA qInv0<>(SB)/8, $0x0a117fffffffffff GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 #define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ @@ -43,10 +43,9 @@ GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 CMOVQCS rb3, ra3; \ // mul(res, x, y *Element) -TEXT ·mul(SB), NOSPLIT, $0-24 +TEXT ·mul(SB), $24-24 - // the algorithm is described here - // https://hackmd.io/@gnark/modular_multiplication + // the algorithm is described in the Element.Mul declaration (.go) // however, to benefit from the ADCX and ADOX carry chains // we split the inner loops in 2: // for i=0 to N-1 @@ -58,6 +57,9 @@ TEXT ·mul(SB), NOSPLIT, $0-24 // (C,t[j-1]) := t[j] + m*q[j] + C // t[N-1] = C + A + NO_LOCAL_POINTERS + CMPB ·supportAdx(SB), $1 + JNE l1 MOVQ x+8(FP), SI // x[0] -> DI @@ -320,7 +322,18 @@ TEXT ·mul(SB), NOSPLIT, $0-24 MOVQ BX, 24(AX) RET -TEXT ·fromMont(SB), NOSPLIT, $0-8 +l1: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·_mulGeneric(SB) + RET + +TEXT ·fromMont(SB), $8-8 + NO_LOCAL_POINTERS // the algorithm is described here // https://hackmd.io/@gnark/modular_multiplication @@ -333,6 +346,8 @@ TEXT ·fromMont(SB), NOSPLIT, $0-8 // for j=1 to N-1 // (C,t[j-1]) := t[j] + m*q[j] + C // t[N-1] = C + CMPB ·supportAdx(SB), $1 + JNE l2 MOVQ res+0(FP), DX MOVQ 0(DX), R14 MOVQ 8(DX), R13 @@ -464,3 +479,9 @@ TEXT ·fromMont(SB), NOSPLIT, $0-8 MOVQ CX, 16(AX) MOVQ BX, 24(AX) RET + +l2: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + CALL ·_fromMontGeneric(SB) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.go new file mode 100644 index 00000000000..e40a9caed55 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.go @@ -0,0 +1,107 @@ +//go:build !purego +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +//go:noescape +func MulBy3(x *Element) + +//go:noescape +func MulBy5(x *Element) + +//go:noescape +func MulBy13(x *Element) + +//go:noescape +func mul(res, x, y *Element) + +//go:noescape +func fromMont(res *Element) + +//go:noescape +func reduce(res *Element) + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +// +//go:noescape +func Butterfly(a, b *Element) + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + mul(z, x, y) + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for doc. + mul(z, x, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.s new file mode 100644 index 00000000000..afe75ff25e2 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_amd64.s @@ -0,0 +1,230 @@ +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x0a11800000000001 +DATA q<>+8(SB)/8, $0x59aa76fed0000001 +DATA q<>+16(SB)/8, $0x60b44d1e5c37b001 +DATA q<>+24(SB)/8, $0x12ab655e9a2ca556 +GLOBL q<>(SB), (RODATA+NOPTR), $32 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x0a117fffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + +TEXT ·reduce(SB), NOSPLIT, $0-8 + MOVQ res+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy3(x *Element) +TEXT ·MulBy3(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy5(x *Element) +TEXT ·MulBy5(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (R15,DI,R8,R9) + REDUCE(DX,CX,BX,SI,R15,DI,R8,R9) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy13(x *Element) +TEXT ·MulBy13(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + MOVQ DX, R11 + MOVQ CX, R12 + MOVQ BX, R13 + MOVQ SI, R14 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ R11, DX + ADCQ R12, CX + ADCQ R13, BX + ADCQ R14, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// Butterfly(a, b *Element) sets a = a + b; b = a - b +TEXT ·Butterfly(SB), NOSPLIT, $0-16 + MOVQ a+0(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ CX, R8 + MOVQ BX, R9 + MOVQ SI, R10 + MOVQ DI, R11 + XORQ AX, AX + MOVQ b+8(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + SUBQ 0(DX), R8 + SBBQ 8(DX), R9 + SBBQ 16(DX), R10 + SBBQ 24(DX), R11 + MOVQ $0x0a11800000000001, R12 + MOVQ $0x59aa76fed0000001, R13 + MOVQ $0x60b44d1e5c37b001, R14 + MOVQ $0x12ab655e9a2ca556, R15 + CMOVQCC AX, R12 + CMOVQCC AX, R13 + CMOVQCC AX, R14 + CMOVQCC AX, R15 + ADDQ R12, R8 + ADCQ R13, R9 + ADCQ R14, R10 + ADCQ R15, R11 + MOVQ R8, 0(DX) + MOVQ R9, 8(DX) + MOVQ R10, 16(DX) + MOVQ R11, 24(DX) + + // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) + + MOVQ a+0(FP), AX + MOVQ CX, 0(AX) + MOVQ BX, 8(AX) + MOVQ SI, 16(AX) + MOVQ DI, 24(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_purego.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_purego.go new file mode 100644 index 00000000000..fe434ed6161 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element_ops_purego.go @@ -0,0 +1,443 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import "math/bits" + +// MulBy3 x *= 3 (mod q) +func MulBy3(x *Element) { + _x := *x + x.Double(x).Add(x, &_x) +} + +// MulBy5 x *= 5 (mod q) +func MulBy5(x *Element) { + _x := *x + x.Double(x).Double(x).Add(x, &_x) +} + +// MulBy13 x *= 13 (mod q) +func MulBy13(x *Element) { + var y = Element{ + 18434640649710993230, + 12067750152132099910, + 14024878721438555919, + 347766975729306096, + } + x.Mul(x, &y) +} + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, y[0]) + u1, t1 = bits.Mul64(v, y[1]) + u2, t2 = bits.Mul64(v, y[2]) + u3, t3 = bits.Mul64(v, y[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for algorithm documentation + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, x[0]) + u1, t1 = bits.Mul64(v, x[1]) + u2, t2 = bits.Mul64(v, x[2]) + u3, t3 = bits.Mul64(v, x[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/vector.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/vector.go new file mode 100644 index 00000000000..00ad8a8986b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/vector.go @@ -0,0 +1,253 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "runtime" + "strings" + "sync" + "sync/atomic" + "unsafe" +) + +// Vector represents a slice of Element. +// +// It implements the following interfaces: +// - Stringer +// - io.WriterTo +// - io.ReaderFrom +// - encoding.BinaryMarshaler +// - encoding.BinaryUnmarshaler +// - sort.Interface +type Vector []Element + +// MarshalBinary implements encoding.BinaryMarshaler +func (vector *Vector) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + + if _, err = vector.WriteTo(&buf); err != nil { + return + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (vector *Vector) UnmarshalBinary(data []byte) error { + r := bytes.NewReader(data) + _, err := vector.ReadFrom(r) + return err +} + +// WriteTo implements io.WriterTo and writes a vector of big endian encoded Element. +// Length of the vector is encoded as a uint32 on the first 4 bytes. +func (vector *Vector) WriteTo(w io.Writer) (int64, error) { + // encode slice length + if err := binary.Write(w, binary.BigEndian, uint32(len(*vector))); err != nil { + return 0, err + } + + n := int64(4) + + var buf [Bytes]byte + for i := 0; i < len(*vector); i++ { + BigEndian.PutElement(&buf, (*vector)[i]) + m, err := w.Write(buf[:]) + n += int64(m) + if err != nil { + return n, err + } + } + return n, nil +} + +// AsyncReadFrom reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +// It consumes the needed bytes from the reader and returns the number of bytes read and an error if any. +// It also returns a channel that will be closed when the validation is done. +// The validation consist of checking that the elements are smaller than the modulus, and +// converting them to montgomery form. +func (vector *Vector) AsyncReadFrom(r io.Reader) (int64, error, chan error) { + chErr := make(chan error, 1) + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + close(chErr) + return int64(read), err, chErr + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + if sliceLen == 0 { + close(chErr) + return n, nil, chErr + } + + bSlice := unsafe.Slice((*byte)(unsafe.Pointer(&(*vector)[0])), sliceLen*Bytes) + read, err := io.ReadFull(r, bSlice) + n += int64(read) + if err != nil { + close(chErr) + return n, err, chErr + } + + go func() { + var cptErrors uint64 + // process the elements in parallel + execute(int(sliceLen), func(start, end int) { + + var z Element + for i := start; i < end; i++ { + // we have to set vector[i] + bstart := i * Bytes + bend := bstart + Bytes + b := bSlice[bstart:bend] + z[0] = binary.BigEndian.Uint64(b[24:32]) + z[1] = binary.BigEndian.Uint64(b[16:24]) + z[2] = binary.BigEndian.Uint64(b[8:16]) + z[3] = binary.BigEndian.Uint64(b[0:8]) + + if !z.smallerThanModulus() { + atomic.AddUint64(&cptErrors, 1) + return + } + z.toMont() + (*vector)[i] = z + } + }) + + if cptErrors > 0 { + chErr <- fmt.Errorf("async read: %d elements failed validation", cptErrors) + } + close(chErr) + }() + return n, nil, chErr +} + +// ReadFrom implements io.ReaderFrom and reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +func (vector *Vector) ReadFrom(r io.Reader) (int64, error) { + + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + return int64(read), err + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + + for i := 0; i < int(sliceLen); i++ { + read, err := io.ReadFull(r, buf[:]) + n += int64(read) + if err != nil { + return n, err + } + (*vector)[i], err = BigEndian.Element(&buf) + if err != nil { + return n, err + } + } + + return n, nil +} + +// String implements fmt.Stringer interface +func (vector Vector) String() string { + var sbb strings.Builder + sbb.WriteByte('[') + for i := 0; i < len(vector); i++ { + sbb.WriteString(vector[i].String()) + if i != len(vector)-1 { + sbb.WriteByte(',') + } + } + sbb.WriteByte(']') + return sbb.String() +} + +// Len is the number of elements in the collection. +func (vector Vector) Len() int { + return len(vector) +} + +// Less reports whether the element with +// index i should sort before the element with index j. +func (vector Vector) Less(i, j int) bool { + return vector[i].Cmp(&vector[j]) == -1 +} + +// Swap swaps the elements with indexes i and j. +func (vector Vector) Swap(i, j int) { + vector[i], vector[j] = vector[j], vector[i] +} + +// TODO @gbotrel make a public package out of that. +// execute executes the work function in parallel. +// this is copy paste from internal/parallel/parallel.go +// as we don't want to generate code importing internal/ +func execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + if nbTasks < 1 { + nbTasks = 1 + } else if nbTasks > 512 { + nbTasks = 512 + } + } + + if nbTasks == 1 { + // no go routines + work(0, nbIterations) + return + } + + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go new file mode 100644 index 00000000000..e1bc1809f45 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go @@ -0,0 +1,1120 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/internal/parallel" + "math/big" + "runtime" +) + +// G1Affine point in affine coordinates +type G1Affine struct { + X, Y fp.Element +} + +// G1Jac is a point with fp.Element coordinates +type G1Jac struct { + X, Y, Z fp.Element +} + +// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +type g1JacExtended struct { + X, Y, ZZ, ZZZ fp.Element +} + +// ------------------------------------------------------------------------------------------------- +// Affine + +// Set sets p to the provided point +func (p *G1Affine) Set(a *G1Affine) *G1Affine { + p.X, p.Y = a.X, a.Y + return p +} + +// setInfinity sets p to O +func (p *G1Affine) setInfinity() *G1Affine { + p.X.SetZero() + p.Y.SetZero() + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { + var _p G1Jac + _p.FromAffine(a) + _p.mulGLV(&_p, s) + p.FromJacobian(&_p) + return p +} + +// ScalarMultiplicationAffine computes and returns p = a ⋅ s +// Takes an affine point and returns a Jacobian point (useful for KZG) +func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { + p.FromAffine(a) + p.mulGLV(p, s) + return p +} + +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + +// Add adds two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { + var p1, p2 G1Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.AddAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Double doubles a point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G1Affine) Double(a *G1Affine) *G1Affine { + var p1 G1Jac + p1.FromAffine(a) + p1.Double(&p1) + p.FromJacobian(&p1) + return p +} + +// Sub subs two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { + var p1, p2 G1Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.SubAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Equal tests if two points (in Affine coordinates) are equal +func (p *G1Affine) Equal(a *G1Affine) bool { + return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) +} + +// Neg computes -G +func (p *G1Affine) Neg(a *G1Affine) *G1Affine { + p.X = a.X + p.Y.Neg(&a.Y) + return p +} + +// FromJacobian rescales a point in Jacobian coord in z=1 plane +func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { + + var a, b fp.Element + + if p1.Z.IsZero() { + p.X.SetZero() + p.Y.SetZero() + return p + } + + a.Inverse(&p1.Z) + b.Square(&a) + p.X.Mul(&p1.X, &b) + p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a) + + return p +} + +// String returns the string representation of the point or "O" if it is infinity +func (p *G1Affine) String() string { + if p.IsInfinity() { + return "O" + } + return "E([" + p.X.String() + "," + p.Y.String() + "])" +} + +// IsInfinity checks if the point is infinity +// in affine, it's encoded as (0,0) +// (0,0) is never on the curve for j=0 curves +func (p *G1Affine) IsInfinity() bool { + return p.X.IsZero() && p.Y.IsZero() +} + +// IsOnCurve returns true if p in on the curve +func (p *G1Affine) IsOnCurve() bool { + var point G1Jac + point.FromAffine(p) + return point.IsOnCurve() // call this function to handle infinity point +} + +// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +func (p *G1Affine) IsInSubGroup() bool { + var _p G1Jac + _p.FromAffine(p) + return _p.IsInSubGroup() +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian + +// Set sets p to the provided point +func (p *G1Jac) Set(a *G1Jac) *G1Jac { + p.X, p.Y, p.Z = a.X, a.Y, a.Z + return p +} + +// Equal tests if two points (in Jacobian coordinates) are equal +func (p *G1Jac) Equal(a *G1Jac) bool { + // If one point is infinity, the other must also be infinity. + if p.Z.IsZero() { + return a.Z.IsZero() + } + // If the other point is infinity, return false since we can't + // the following checks would be incorrect. + if a.Z.IsZero() { + return false + } + + var pZSquare, aZSquare fp.Element + pZSquare.Square(&p.Z) + aZSquare.Square(&a.Z) + + var lhs, rhs fp.Element + lhs.Mul(&p.X, &aZSquare) + rhs.Mul(&a.X, &pZSquare) + if !lhs.Equal(&rhs) { + return false + } + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) + rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + + return lhs.Equal(&rhs) +} + +// Neg computes -G +func (p *G1Jac) Neg(a *G1Jac) *G1Jac { + *p = *a + p.Y.Neg(&a.Y) + return p +} + +// SubAssign subtracts two points on the curve +func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(a) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// AddAssign point addition in montgomery form +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl +func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { + + // p is infinity, return a + if p.Z.IsZero() { + p.Set(a) + return p + } + + // a is infinity, return p + if a.Z.IsZero() { + return p + } + + var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element + Z1Z1.Square(&a.Z) + Z2Z2.Square(&p.Z) + U1.Mul(&a.X, &Z2Z2) + U2.Mul(&p.X, &Z1Z1) + S1.Mul(&a.Y, &p.Z). + Mul(&S1, &Z2Z2) + S2.Mul(&p.Y, &a.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U1.Equal(&U2) && S1.Equal(&S2) { + return p.DoubleAssign() + } + + H.Sub(&U2, &U1) + I.Double(&H). + Square(&I) + J.Mul(&H, &I) + r.Sub(&S2, &S1).Double(&r) + V.Mul(&U1, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + S1.Mul(&S1, &J).Double(&S1) + p.Y.Sub(&p.Y, &S1) + p.Z.Add(&p.Z, &a.Z) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &Z2Z2). + Mul(&p.Z, &H) + + return p +} + +// AddMixed point addition +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl +func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.Z.IsZero() { + p.X = a.X + p.Y = a.Y + p.Z.SetOne() + return p + } + + var Z1Z1, U2, S2, H, HH, I, J, r, V fp.Element + Z1Z1.Square(&p.Z) + U2.Mul(&a.X, &Z1Z1) + S2.Mul(&a.Y, &p.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U2.Equal(&p.X) && S2.Equal(&p.Y) { + return p.DoubleAssign() + } + + H.Sub(&U2, &p.X) + HH.Square(&H) + I.Double(&HH).Double(&I) + J.Mul(&H, &I) + r.Sub(&S2, &p.Y).Double(&r) + V.Mul(&p.X, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + J.Mul(&J, &p.Y).Double(&J) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + p.Y.Sub(&p.Y, &J) + p.Z.Add(&p.Z, &H) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &HH) + + return p +} + +// Double doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G1Jac) Double(q *G1Jac) *G1Jac { + p.Set(q) + p.DoubleAssign() + return p +} + +// DoubleAssign doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G1Jac) DoubleAssign() *G1Jac { + + var XX, YY, YYYY, ZZ, S, M, T fp.Element + + XX.Square(&p.X) + YY.Square(&p.Y) + YYYY.Square(&YY) + ZZ.Square(&p.Z) + S.Add(&p.X, &YY) + S.Square(&S). + Sub(&S, &XX). + Sub(&S, &YYYY). + Double(&S) + M.Double(&XX).Add(&M, &XX) + p.Z.Add(&p.Z, &p.Y). + Square(&p.Z). + Sub(&p.Z, &YY). + Sub(&p.Z, &ZZ) + T.Square(&M) + p.X = T + T.Double(&S) + p.X.Sub(&p.X, &T) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M) + YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY) + p.Y.Sub(&p.Y, &YYYY) + + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(a, s) +} + +// String returns canonical representation of the point in affine coordinates +func (p *G1Jac) String() string { + _p := G1Affine{} + _p.FromJacobian(p) + return _p.String() +} + +// FromAffine sets p = Q, p in Jacobian, Q in affine +func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { + if Q.IsInfinity() { + p.Z.SetZero() + p.X.SetOne() + p.Y.SetOne() + return p + } + p.Z.SetOne() + p.X.Set(&Q.X) + p.Y.Set(&Q.Y) + return p +} + +// IsOnCurve returns true if p in on the curve +func (p *G1Jac) IsOnCurve() bool { + var left, right, tmp fp.Element + left.Square(&p.Y) + right.Square(&p.X).Mul(&right, &p.X) + tmp.Square(&p.Z). + Square(&tmp). + Mul(&tmp, &p.Z). + Mul(&tmp, &p.Z). + Mul(&tmp, &bCurveCoeff) + right.Add(&right, &tmp) + return left.Equal(&right) +} + +// IsInSubGroup returns true if p is on the r-torsion, false otherwise. +// Z[r,0]+Z[-lambdaG1Affine, 1] is the kernel +// of (u,v)->u+lambdaG1Affinev mod r. Expressing r, lambdaG1Affine as +// polynomials in x, a short vector of this Zmodule is +// 1, x². So we check that p+x²ϕ(p) +// is the infinity. +func (p *G1Jac) IsInSubGroup() bool { + + var res G1Jac + + res.phi(p). + ScalarMultiplication(&res, &xGen). + ScalarMultiplication(&res, &xGen). + AddAssign(p) + + return res.IsOnCurve() && res.Z.IsZero() + +} + +// mulWindowed computes a 2-bits windowed scalar multiplication +func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { + + var res G1Jac + var ops [3]G1Jac + + ops[0].Set(a) + if s.Sign() == -1 { + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) + ops[1].Double(&ops[0]) + ops[2].Set(&ops[0]).AddAssign(&ops[1]) + + b := s.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.DoubleAssign().DoubleAssign() + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.AddAssign(&ops[c-1]) + } + mask = mask >> 2 + } + } + p.Set(&res) + + return p + +} + +// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p +// where w is a third root of unity in 𝔽p +func (p *G1Jac) phi(a *G1Jac) *G1Jac { + p.Set(a) + p.X.Mul(&p.X, &thirdRootOneG1) + return p +} + +// mulGLV computes the scalar multiplication using a windowed-GLV method +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { + + var table [15]G1Jac + var res G1Jac + var k1, k2 fr.Element + + res.Set(&g1Infinity) + + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a + table[0].Set(a) + table[3].phi(a) + + // split the scalar, modifies ±a, ϕ(a) accordingly + k := ecc.SplitScalar(s, &glvBasis) + + if k[0].Sign() == -1 { + k[0].Neg(&k[0]) + table[0].Neg(&table[0]) + } + if k[1].Sign() == -1 { + k[1].Neg(&k[1]) + table[3].Neg(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max + // this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift + k1 = k1.SetBigInt(&k[0]).Bits() + k2 = k2.SetBigInt(&k[1]).Bits() + + // we don't target constant-timeness so we check first if we increase the bounds or not + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (k1[i] & mask) >> (62 - 2*j) + b2 := (k2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { + var _p G1Jac + _p.FromAffine(a) + _p.ClearCofactor(&_p) + p.FromJacobian(&_p) + return p +} + +// ClearCofactor maps a point in E(Fp) to E(Fp)[r] +func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { + // cf https://eprint.iacr.org/2019/403.pdf, 5 + var res G1Jac + res.ScalarMultiplication(a, &xGen).Neg(&res).AddAssign(a) + p.Set(&res) + return p + +} + +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.Set(&g1Gen) + p2.FromAffine(a) + + var table [15]G1Jac + + var k1, k2 big.Int + if s1.Sign() == -1 { + k1.Neg(s1) + table[0].Neg(&p1) + } else { + k1.Set(s1) + table[0].Set(&p1) + } + if s2.Sign() == -1 { + k2.Neg(s2) + table[3].Neg(&p2) + } else { + k2.Set(s2) + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() + + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian extended + +// Set sets p to the provided point +func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ + return p +} + +// setInfinity sets p to O +func (p *g1JacExtended) setInfinity() *g1JacExtended { + p.X.SetOne() + p.Y.SetOne() + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p +} + +func (p *g1JacExtended) IsZero() bool { + return p.ZZ.IsZero() +} + +// fromJacExtended sets Q in affine coordinates +func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { + if Q.ZZ.IsZero() { + p.X = fp.Element{} + p.Y = fp.Element{} + return p + } + p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + return p +} + +// fromJacExtended sets Q in Jacobian coordinates +func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { + if Q.ZZ.IsZero() { + p.Set(&g1Infinity) + return p + } + p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) + p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) + p.Z.Set(&Q.ZZZ) + return p +} + +// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity +func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { + p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.Z = Q.ZZZ + return p +} + +// add point in Jacobian extended coordinates +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s +func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { + //if q is infinity return p + if q.ZZ.IsZero() { + return p + } + // p is infinity, return q + if p.ZZ.IsZero() { + p.Set(q) + return p + } + + var A, B, U1, U2, S1, S2 fp.Element + + // p2: q, p1: p + U2.Mul(&q.X, &p.ZZ) + U1.Mul(&p.X, &q.ZZ) + A.Sub(&U2, &U1) + S2.Mul(&q.Y, &p.ZZZ) + S1.Mul(&p.Y, &q.ZZZ) + B.Sub(&S2, &S1) + + if A.IsZero() { + if B.IsZero() { + return p.double(q) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var P, R, PP, PPP, Q, V fp.Element + P.Sub(&U2, &U1) + R.Sub(&S2, &S1) + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&U1, &PP) + V.Mul(&S1, &PPP) + + p.X.Square(&R). + Sub(&p.X, &PPP). + Sub(&p.X, &Q). + Sub(&p.X, &Q) + p.Y.Sub(&Q, &p.X). + Mul(&p.Y, &R). + Sub(&p.Y, &V) + p.ZZ.Mul(&p.ZZ, &q.ZZ). + Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &q.ZZZ). + Mul(&p.ZZZ, &PPP) + + return p +} + +// double point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +// since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well +func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { + var U, V, W, S, XX, M fp.Element + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + U.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S). + Sub(&p.X, &S) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &U) + p.ZZ.Mul(&V, &q.ZZ) + p.ZZZ.Mul(&W, &q.ZZZ) + + return p +} + +// subMixed same as addMixed, but will negate a.Y +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y.Neg(&a.Y) + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fp.Element + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleNegMixed(a) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// addMixed +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y = a.Y + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fp.Element + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleMixed(a) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// doubleNegMixed same as double, but will negate q.Y +func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { + + var U, V, W, S, XX, M, S2, L fp.Element + + U.Double(&q.Y) + U.Neg(&U) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Add(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// doubleMixed point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { + + var U, V, W, S, XX, M, S2, L fp.Element + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) + zeroes := make([]bool, len(points)) + accumulator := fp.One() + + // batch invert all points[].Z coordinates with Montgomery batch inversion trick + // (stores points[].Z^-1 in result[i].X to avoid allocating a slice of fr.Elements) + for i := 0; i < len(points); i++ { + if points[i].Z.IsZero() { + zeroes[i] = true + continue + } + result[i].X = accumulator + accumulator.Mul(&accumulator, &points[i].Z) + } + + var accInverse fp.Element + accInverse.Inverse(&accumulator) + + for i := len(points) - 1; i >= 0; i-- { + if zeroes[i] { + // do nothing, (X=0, Y=0) is infinity point in affine + continue + } + result[i].X.Mul(&result[i].X, &accInverse) + accInverse.Mul(&accInverse, &points[i].Z) + } + + // batch convert to affine. + parallel.Execute(len(points), func(start, end int) { + for i := start; i < end; i++ { + if zeroes[i] { + // do nothing, (X=0, Y=0) is infinity point in affine + continue + } + var a, b fp.Element + a = result[i].X + b.Square(&a) + result[i].X.Mul(&points[i].X, &b) + result[i].Y.Mul(&points[i].Y, &b). + Mul(&result[i].Y, &a) + } + }) + + return result +} + +// BatchScalarMultiplicationG1 multiplies the same base by all scalars +// and return resulting points in affine coordinates +// uses a simple windowed-NAF like exponentiation algorithm +func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { + // approximate cost in group ops is + // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) + + nbPoints := uint64(len(scalars)) + min := ^uint64(0) + bestC := 0 + for c := 2; c <= 16; c++ { + cost := uint64(1 << (c - 1)) // pre compute the table + nbChunks := computeNbChunks(uint64(c)) + cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add + if cost < min { + min = cost + bestC = c + } + } + c := uint64(bestC) // window size + nbChunks := int(computeNbChunks(c)) + + // last window may be slightly larger than c; in which case we need to compute one + // extra element in the baseTable + maxC := lastC(c) + if c > maxC { + maxC = c + } + + // precompute all powers of base for our window + // note here that if performance is critical, we can implement as in the msmX methods + // this allocation to be on the stack + baseTable := make([]G1Jac, (1 << (maxC - 1))) + baseTable[0].FromAffine(base) + for i := 1; i < len(baseTable); i++ { + baseTable[i] = baseTable[i-1] + baseTable[i].AddMixed(base) + } + // convert our base exp table into affine to use AddMixed + baseTableAff := BatchJacobianToAffineG1(baseTable) + toReturn := make([]G1Jac, len(scalars)) + + // partition the scalars into digits + digits, _ := partitionScalars(scalars, c, runtime.NumCPU()) + + // for each digit, take value in the base table, double it c time, voilà. + parallel.Execute(len(scalars), func(start, end int) { + var p G1Jac + for i := start; i < end; i++ { + p.Set(&g1Infinity) + for chunk := nbChunks - 1; chunk >= 0; chunk-- { + if chunk != nbChunks-1 { + for j := uint64(0); j < c; j++ { + p.DoubleAssign() + } + } + offset := chunk * len(scalars) + digit := digits[i+offset] + + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + p.AddMixed(&baseTableAff[(digit>>1)-1]) + } else { + // sub + t := baseTableAff[digit>>1] + t.Neg(&t) + p.AddMixed(&t) + } + } + + // set our result point + toReturn[i] = p + + } + }) + toReturnAff := BatchJacobianToAffineG1(toReturn) + return toReturnAff +} + +// batch add affine coordinates +// using batch inversion +// special cases (doubling, infinity) must be filtered out before this call +func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { + var lambda, lambdain TC + + // add part + for j := 0; j < batchSize; j++ { + lambdain[j].Sub(&(*P)[j].X, &(*R)[j].X) + } + + // invert denominator using montgomery batch invert technique + { + var accumulator fp.Element + lambda[0].SetOne() + accumulator.Set(&lambdain[0]) + + for i := 1; i < batchSize; i++ { + lambda[i] = accumulator + accumulator.Mul(&accumulator, &lambdain[i]) + } + + accumulator.Inverse(&accumulator) + + for i := batchSize - 1; i > 0; i-- { + lambda[i].Mul(&lambda[i], &accumulator) + accumulator.Mul(&accumulator, &lambdain[i]) + } + lambda[0].Set(&accumulator) + } + + var d fp.Element + var rr G1Affine + + // add part + for j := 0; j < batchSize; j++ { + // computa lambda + d.Sub(&(*P)[j].Y, &(*R)[j].Y) + lambda[j].Mul(&lambda[j], &d) + + // compute X, Y + rr.X.Square(&lambda[j]) + rr.X.Sub(&rr.X, &(*R)[j].X) + rr.X.Sub(&rr.X, &(*P)[j].X) + d.Sub(&(*R)[j].X, &rr.X) + rr.Y.Mul(&lambda[j], &d) + rr.Y.Sub(&rr.Y, &(*R)[j].Y) + (*R)[j].Set(&rr) + } +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go new file mode 100644 index 00000000000..c256d8210e8 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go @@ -0,0 +1,1036 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" + "math/big" + "runtime" +) + +// G2Affine point in affine coordinates +type G2Affine struct { + X, Y fptower.E2 +} + +// G2Jac is a point with fptower.E2 coordinates +type G2Jac struct { + X, Y, Z fptower.E2 +} + +// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +type g2JacExtended struct { + X, Y, ZZ, ZZZ fptower.E2 +} + +// g2Proj point in projective coordinates +type g2Proj struct { + x, y, z fptower.E2 +} + +// ------------------------------------------------------------------------------------------------- +// Affine + +// Set sets p to the provided point +func (p *G2Affine) Set(a *G2Affine) *G2Affine { + p.X, p.Y = a.X, a.Y + return p +} + +// setInfinity sets p to O +func (p *G2Affine) setInfinity() *G2Affine { + p.X.SetZero() + p.Y.SetZero() + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { + var _p G2Jac + _p.FromAffine(a) + _p.mulGLV(&_p, s) + p.FromJacobian(&_p) + return p +} + +// Add adds two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { + var p1, p2 G2Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.AddAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Double doubles a point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G2Affine) Double(a *G2Affine) *G2Affine { + var p1 G2Jac + p1.FromAffine(a) + p1.Double(&p1) + p.FromJacobian(&p1) + return p +} + +// Sub subs two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { + var p1, p2 G2Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.SubAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Equal tests if two points (in Affine coordinates) are equal +func (p *G2Affine) Equal(a *G2Affine) bool { + return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) +} + +// Neg computes -G +func (p *G2Affine) Neg(a *G2Affine) *G2Affine { + p.X = a.X + p.Y.Neg(&a.Y) + return p +} + +// FromJacobian rescales a point in Jacobian coord in z=1 plane +func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { + + var a, b fptower.E2 + + if p1.Z.IsZero() { + p.X.SetZero() + p.Y.SetZero() + return p + } + + a.Inverse(&p1.Z) + b.Square(&a) + p.X.Mul(&p1.X, &b) + p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a) + + return p +} + +// String returns the string representation of the point or "O" if it is infinity +func (p *G2Affine) String() string { + if p.IsInfinity() { + return "O" + } + return "E([" + p.X.String() + "," + p.Y.String() + "])" +} + +// IsInfinity checks if the point is infinity +// in affine, it's encoded as (0,0) +// (0,0) is never on the curve for j=0 curves +func (p *G2Affine) IsInfinity() bool { + return p.X.IsZero() && p.Y.IsZero() +} + +// IsOnCurve returns true if p in on the curve +func (p *G2Affine) IsOnCurve() bool { + var point G2Jac + point.FromAffine(p) + return point.IsOnCurve() // call this function to handle infinity point +} + +// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +func (p *G2Affine) IsInSubGroup() bool { + var _p G2Jac + _p.FromAffine(p) + return _p.IsInSubGroup() +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian + +// Set sets p to the provided point +func (p *G2Jac) Set(a *G2Jac) *G2Jac { + p.X, p.Y, p.Z = a.X, a.Y, a.Z + return p +} + +// Equal tests if two points (in Jacobian coordinates) are equal +func (p *G2Jac) Equal(a *G2Jac) bool { + // If one point is infinity, the other must also be infinity. + if p.Z.IsZero() { + return a.Z.IsZero() + } + // If the other point is infinity, return false since we can't + // the following checks would be incorrect. + if a.Z.IsZero() { + return false + } + + var pZSquare, aZSquare fptower.E2 + pZSquare.Square(&p.Z) + aZSquare.Square(&a.Z) + + var lhs, rhs fptower.E2 + lhs.Mul(&p.X, &aZSquare) + rhs.Mul(&a.X, &pZSquare) + if !lhs.Equal(&rhs) { + return false + } + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) + rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + + return lhs.Equal(&rhs) +} + +// Neg computes -G +func (p *G2Jac) Neg(a *G2Jac) *G2Jac { + *p = *a + p.Y.Neg(&a.Y) + return p +} + +// SubAssign subtracts two points on the curve +func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(a) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// AddAssign point addition in montgomery form +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl +func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { + + // p is infinity, return a + if p.Z.IsZero() { + p.Set(a) + return p + } + + // a is infinity, return p + if a.Z.IsZero() { + return p + } + + var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E2 + Z1Z1.Square(&a.Z) + Z2Z2.Square(&p.Z) + U1.Mul(&a.X, &Z2Z2) + U2.Mul(&p.X, &Z1Z1) + S1.Mul(&a.Y, &p.Z). + Mul(&S1, &Z2Z2) + S2.Mul(&p.Y, &a.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U1.Equal(&U2) && S1.Equal(&S2) { + return p.DoubleAssign() + } + + H.Sub(&U2, &U1) + I.Double(&H). + Square(&I) + J.Mul(&H, &I) + r.Sub(&S2, &S1).Double(&r) + V.Mul(&U1, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + S1.Mul(&S1, &J).Double(&S1) + p.Y.Sub(&p.Y, &S1) + p.Z.Add(&p.Z, &a.Z) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &Z2Z2). + Mul(&p.Z, &H) + + return p +} + +// AddMixed point addition +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl +func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.Z.IsZero() { + p.X = a.X + p.Y = a.Y + p.Z.SetOne() + return p + } + + var Z1Z1, U2, S2, H, HH, I, J, r, V fptower.E2 + Z1Z1.Square(&p.Z) + U2.Mul(&a.X, &Z1Z1) + S2.Mul(&a.Y, &p.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U2.Equal(&p.X) && S2.Equal(&p.Y) { + return p.DoubleAssign() + } + + H.Sub(&U2, &p.X) + HH.Square(&H) + I.Double(&HH).Double(&I) + J.Mul(&H, &I) + r.Sub(&S2, &p.Y).Double(&r) + V.Mul(&p.X, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + J.Mul(&J, &p.Y).Double(&J) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + p.Y.Sub(&p.Y, &J) + p.Z.Add(&p.Z, &H) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &HH) + + return p +} + +// Double doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G2Jac) Double(q *G2Jac) *G2Jac { + p.Set(q) + p.DoubleAssign() + return p +} + +// DoubleAssign doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G2Jac) DoubleAssign() *G2Jac { + + var XX, YY, YYYY, ZZ, S, M, T fptower.E2 + + XX.Square(&p.X) + YY.Square(&p.Y) + YYYY.Square(&YY) + ZZ.Square(&p.Z) + S.Add(&p.X, &YY) + S.Square(&S). + Sub(&S, &XX). + Sub(&S, &YYYY). + Double(&S) + M.Double(&XX).Add(&M, &XX) + p.Z.Add(&p.Z, &p.Y). + Square(&p.Z). + Sub(&p.Z, &YY). + Sub(&p.Z, &ZZ) + T.Square(&M) + p.X = T + T.Double(&S) + p.X.Sub(&p.X, &T) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M) + YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY) + p.Y.Sub(&p.Y, &YYYY) + + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(a, s) +} + +// String returns canonical representation of the point in affine coordinates +func (p *G2Jac) String() string { + _p := G2Affine{} + _p.FromJacobian(p) + return _p.String() +} + +// FromAffine sets p = Q, p in Jacobian, Q in affine +func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { + if Q.IsInfinity() { + p.Z.SetZero() + p.X.SetOne() + p.Y.SetOne() + return p + } + p.Z.SetOne() + p.X.Set(&Q.X) + p.Y.Set(&Q.Y) + return p +} + +// IsOnCurve returns true if p in on the curve +func (p *G2Jac) IsOnCurve() bool { + var left, right, tmp fptower.E2 + left.Square(&p.Y) + right.Square(&p.X).Mul(&right, &p.X) + tmp.Square(&p.Z). + Square(&tmp). + Mul(&tmp, &p.Z). + Mul(&tmp, &p.Z). + Mul(&tmp, &bTwistCurveCoeff) + right.Add(&right, &tmp) + return left.Equal(&right) +} + +// https://eprint.iacr.org/2021/1130.pdf, sec.4 +// and https://eprint.iacr.org/2022/352.pdf, sec. 4.2 +// ψ(p) = [x₀]P +func (p *G2Jac) IsInSubGroup() bool { + var res, tmp G2Jac + tmp.psi(p) + res.ScalarMultiplication(p, &xGen). + SubAssign(&tmp) + + return res.IsOnCurve() && res.Z.IsZero() +} + +// mulWindowed computes a 2-bits windowed scalar multiplication +func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { + + var res G2Jac + var ops [3]G2Jac + + ops[0].Set(a) + if s.Sign() == -1 { + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) + ops[1].Double(&ops[0]) + ops[2].Set(&ops[0]).AddAssign(&ops[1]) + + b := s.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.DoubleAssign().DoubleAssign() + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.AddAssign(&ops[c-1]) + } + mask = mask >> 2 + } + } + p.Set(&res) + + return p + +} + +// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E +func (p *G2Jac) psi(a *G2Jac) *G2Jac { + p.Set(a) + p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) + p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) + p.Z.Conjugate(&p.Z) + return p +} + +// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p +// where w is a third root of unity in 𝔽p +func (p *G2Jac) phi(a *G2Jac) *G2Jac { + p.Set(a) + p.X.MulByElement(&p.X, &thirdRootOneG2) + return p +} + +// mulGLV computes the scalar multiplication using a windowed-GLV method +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { + + var table [15]G2Jac + var res G2Jac + var k1, k2 fr.Element + + res.Set(&g2Infinity) + + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a + table[0].Set(a) + table[3].phi(a) + + // split the scalar, modifies ±a, ϕ(a) accordingly + k := ecc.SplitScalar(s, &glvBasis) + + if k[0].Sign() == -1 { + k[0].Neg(&k[0]) + table[0].Neg(&table[0]) + } + if k[1].Sign() == -1 { + k[1].Neg(&k[1]) + table[3].Neg(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max + // this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift + k1 = k1.SetBigInt(&k[0]).Bits() + k2 = k2.SetBigInt(&k[1]).Bits() + + // we don't target constant-timeness so we check first if we increase the bounds or not + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (k1[i] & mask) >> (62 - 2*j) + b2 := (k2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { + var _p G2Jac + _p.FromAffine(a) + _p.ClearCofactor(&_p) + p.FromJacobian(&_p) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { + // https://eprint.iacr.org/2017/419.pdf, 4.1 + var xg, xxg, res, t G2Jac + xg.ScalarMultiplication(a, &xGen) + xxg.ScalarMultiplication(&xg, &xGen) + + res.Set(&xxg). + SubAssign(&xg). + SubAssign(a) + + t.Set(&xg). + SubAssign(a). + psi(&t) + + res.AddAssign(&t) + + t.Double(a) + t.X.MulByElement(&t.X, &thirdRootOneG1) + + res.SubAssign(&t) + + p.Set(&res) + + return p + +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian extended + +// Set sets p to the provided point +func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ + return p +} + +// setInfinity sets p to O +func (p *g2JacExtended) setInfinity() *g2JacExtended { + p.X.SetOne() + p.Y.SetOne() + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p +} + +func (p *g2JacExtended) IsZero() bool { + return p.ZZ.IsZero() +} + +// fromJacExtended sets Q in affine coordinates +func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { + if Q.ZZ.IsZero() { + p.X = fptower.E2{} + p.Y = fptower.E2{} + return p + } + p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + return p +} + +// fromJacExtended sets Q in Jacobian coordinates +func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { + if Q.ZZ.IsZero() { + p.Set(&g2Infinity) + return p + } + p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) + p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) + p.Z.Set(&Q.ZZZ) + return p +} + +// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity +func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { + p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.Z = Q.ZZZ + return p +} + +// add point in Jacobian extended coordinates +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s +func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { + //if q is infinity return p + if q.ZZ.IsZero() { + return p + } + // p is infinity, return q + if p.ZZ.IsZero() { + p.Set(q) + return p + } + + var A, B, U1, U2, S1, S2 fptower.E2 + + // p2: q, p1: p + U2.Mul(&q.X, &p.ZZ) + U1.Mul(&p.X, &q.ZZ) + A.Sub(&U2, &U1) + S2.Mul(&q.Y, &p.ZZZ) + S1.Mul(&p.Y, &q.ZZZ) + B.Sub(&S2, &S1) + + if A.IsZero() { + if B.IsZero() { + return p.double(q) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var P, R, PP, PPP, Q, V fptower.E2 + P.Sub(&U2, &U1) + R.Sub(&S2, &S1) + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&U1, &PP) + V.Mul(&S1, &PPP) + + p.X.Square(&R). + Sub(&p.X, &PPP). + Sub(&p.X, &Q). + Sub(&p.X, &Q) + p.Y.Sub(&Q, &p.X). + Mul(&p.Y, &R). + Sub(&p.Y, &V) + p.ZZ.Mul(&p.ZZ, &q.ZZ). + Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &q.ZZZ). + Mul(&p.ZZZ, &PPP) + + return p +} + +// double point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +// since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well +func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { + var U, V, W, S, XX, M fptower.E2 + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + U.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S). + Sub(&p.X, &S) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &U) + p.ZZ.Mul(&V, &q.ZZ) + p.ZZZ.Mul(&W, &q.ZZZ) + + return p +} + +// subMixed same as addMixed, but will negate a.Y +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y.Neg(&a.Y) + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fptower.E2 + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleNegMixed(a) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fptower.E2 + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// addMixed +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y = a.Y + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fptower.E2 + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleMixed(a) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fptower.E2 + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// doubleNegMixed same as double, but will negate q.Y +func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { + + var U, V, W, S, XX, M, S2, L fptower.E2 + + U.Double(&q.Y) + U.Neg(&U) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Add(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// doubleMixed point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { + + var U, V, W, S, XX, M, S2, L fptower.E2 + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// ------------------------------------------------------------------------------------------------- +// Homogenous projective + +// Set sets p to the provided point +func (p *g2Proj) Set(a *g2Proj) *g2Proj { + p.x, p.y, p.z = a.x, a.y, a.z + return p +} + +// Neg computes -G +func (p *g2Proj) Neg(a *g2Proj) *g2Proj { + *p = *a + p.y.Neg(&a.y) + return p +} + +// FromAffine sets p = Q, p in homogenous projective, Q in affine +func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { + if Q.X.IsZero() && Q.Y.IsZero() { + p.z.SetZero() + p.x.SetOne() + p.y.SetOne() + return p + } + p.z.SetOne() + p.x.Set(&Q.X) + p.y.Set(&Q.Y) + return p +} + +// BatchScalarMultiplicationG2 multiplies the same base by all scalars +// and return resulting points in affine coordinates +// uses a simple windowed-NAF like exponentiation algorithm +func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { + // approximate cost in group ops is + // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) + + nbPoints := uint64(len(scalars)) + min := ^uint64(0) + bestC := 0 + for c := 2; c <= 16; c++ { + cost := uint64(1 << (c - 1)) // pre compute the table + nbChunks := computeNbChunks(uint64(c)) + cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add + if cost < min { + min = cost + bestC = c + } + } + c := uint64(bestC) // window size + nbChunks := int(computeNbChunks(c)) + + // last window may be slightly larger than c; in which case we need to compute one + // extra element in the baseTable + maxC := lastC(c) + if c > maxC { + maxC = c + } + + // precompute all powers of base for our window + // note here that if performance is critical, we can implement as in the msmX methods + // this allocation to be on the stack + baseTable := make([]G2Jac, (1 << (maxC - 1))) + baseTable[0].FromAffine(base) + for i := 1; i < len(baseTable); i++ { + baseTable[i] = baseTable[i-1] + baseTable[i].AddMixed(base) + } + toReturn := make([]G2Affine, len(scalars)) + + // partition the scalars into digits + digits, _ := partitionScalars(scalars, c, runtime.NumCPU()) + + // for each digit, take value in the base table, double it c time, voilà. + parallel.Execute(len(scalars), func(start, end int) { + var p G2Jac + for i := start; i < end; i++ { + p.Set(&g2Infinity) + for chunk := nbChunks - 1; chunk >= 0; chunk-- { + if chunk != nbChunks-1 { + for j := uint64(0); j < c; j++ { + p.DoubleAssign() + } + } + offset := chunk * len(scalars) + digit := digits[i+offset] + + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + p.AddAssign(&baseTable[(digit>>1)-1]) + } else { + // sub + t := baseTable[digit>>1] + t.Neg(&t) + p.AddAssign(&t) + } + } + + // set our result point + toReturn[i].FromJacobian(&p) + + } + }) + return toReturn +} + +// batch add affine coordinates +// using batch inversion +// special cases (doubling, infinity) must be filtered out before this call +func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { + var lambda, lambdain TC + + // add part + for j := 0; j < batchSize; j++ { + lambdain[j].Sub(&(*P)[j].X, &(*R)[j].X) + } + + // invert denominator using montgomery batch invert technique + { + var accumulator fptower.E2 + lambda[0].SetOne() + accumulator.Set(&lambdain[0]) + + for i := 1; i < batchSize; i++ { + lambda[i] = accumulator + accumulator.Mul(&accumulator, &lambdain[i]) + } + + accumulator.Inverse(&accumulator) + + for i := batchSize - 1; i > 0; i-- { + lambda[i].Mul(&lambda[i], &accumulator) + accumulator.Mul(&accumulator, &lambdain[i]) + } + lambda[0].Set(&accumulator) + } + + var d fptower.E2 + var rr G2Affine + + // add part + for j := 0; j < batchSize; j++ { + // computa lambda + d.Sub(&(*P)[j].Y, &(*R)[j].Y) + lambda[j].Mul(&lambda[j], &d) + + // compute X, Y + rr.X.Square(&lambda[j]) + rr.X.Sub(&rr.X, &(*R)[j].X) + rr.X.Sub(&rr.X, &(*P)[j].X) + d.Sub(&(*R)[j].X, &rr.X) + rr.Y.Mul(&lambda[j], &d) + rr.Y.Sub(&rr.Y, &(*R)[j].Y) + (*R)[j].Set(&rr) + } +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g1.go new file mode 100644 index 00000000000..20306ba879b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g1.go @@ -0,0 +1,329 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + + "math/big" +) + +//Note: This only works for simple extensions + +func g1IsogenyXNumerator(dst *fp.Element, x *fp.Element) { + g1EvalPolynomial(dst, + false, + []fp.Element{ + {9381318728011785451, 8795417190580748876, 15171640721257608922, 11815547924113428908, 15499908520243100994, 75408755324413256}, + {12414498063752772717, 9915153185132073893, 5598625970987438951, 3342254783599619135, 3349592178919125510, 9993871847068096}, + {4662210776746950618, 10687085762534440940, 7484820859645808636, 2221301482234255553, 10609677459585442106, 9950135580589350}, + }, + x) +} + +func g1IsogenyXDenominator(dst *fp.Element, x *fp.Element) { + g1EvalPolynomial(dst, + true, + []fp.Element{ + {12764504107591987636, 2767124593109192342, 3947759810240204190, 13369019134398476541, 13398368715676502040, 39975487388272384}, + }, + x) +} + +func g1IsogenyYNumerator(dst *fp.Element, x *fp.Element, y *fp.Element) { + var _dst fp.Element + g1EvalPolynomial(&_dst, + false, + []fp.Element{ + {13844135623281082635, 637899392157745290, 5176720401210677272, 4780940929980393029, 13803251044890140836, 51447363642369244}, + {512010462697120695, 609509684909242946, 13763343875136563934, 2839514380057330869, 15407015190976871917, 114223893455203604}, + {14191436515319700132, 6479619458373647736, 9513056055282499867, 15178407828209519654, 12166396751953702822, 75539964123849493}, + {2331105388373475309, 5343542881267220470, 12965782466677680126, 1110650741117127776, 5304838729792721053, 4975067790294675}, + }, + x) + + dst.Mul(&_dst, y) +} + +func g1IsogenyYDenominator(dst *fp.Element, x *fp.Element) { + g1EvalPolynomial(dst, + true, + []fp.Element{ + {8694832399336342723, 13482963304561246841, 6984108042366343277, 8355250559073919616, 16937021447778317421, 44890599540624877}, + {1100361703846424922, 5005767817281133373, 917019320419705433, 14251746270386956490, 5522097789867984932, 4443041874334878}, + {1400024175356859676, 8301373779327577028, 11843279430720612570, 3213569255776326391, 3301617999610402890, 119926462164817154}, + }, + x) +} + +func g1Isogeny(p *G1Affine) { + + den := make([]fp.Element, 2) + + g1IsogenyYDenominator(&den[1], &p.X) + g1IsogenyXDenominator(&den[0], &p.X) + + g1IsogenyYNumerator(&p.Y, &p.X, &p.Y) + g1IsogenyXNumerator(&p.X, &p.X) + + den = fp.BatchInvert(den) + + p.X.Mul(&p.X, &den[0]) + p.Y.Mul(&p.Y, &den[1]) +} + +// g1SqrtRatio computes the square root of u/v and returns 0 iff u/v was indeed a quadratic residue +// if not, we get sqrt(Z * u / v). Recall that Z is non-residue +// If v = 0, u/v is meaningless and the output is unspecified, without raising an error. +// The main idea is that since the computation of the square root involves taking large powers of u/v, the inversion of v can be avoided +func g1SqrtRatio(z *fp.Element, u *fp.Element, v *fp.Element) uint64 { + + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-sqrt_ratio-for-any-field + + tv1 := fp.Element{7563926049028936178, 2688164645460651601, 12112688591437172399, 3177973240564633687, 14764383749841851163, 52487407124055189} //tv1 = c6 + + var tv2, tv3, tv4, tv5 fp.Element + var exp big.Int + // c4 = 70368744177663 = 2⁴⁶ - 1 + // q is odd so c1 is at least 1. + exp.SetBytes([]byte{63, 255, 255, 255, 255, 255}) + + tv2.Exp(*v, &exp) // 2. tv2 = vᶜ⁴ + tv3.Square(&tv2) // 3. tv3 = tv2² + tv3.Mul(&tv3, v) // 4. tv3 = tv3 * v + tv5.Mul(u, &tv3) // 5. tv5 = u * tv3 + + // c3 = 1837921289030710838195067919506396475074392872918698035817074744121558668640693829665401097909504529 + exp.SetBytes([]byte{3, 92, 116, 140, 47, 138, 33, 213, 140, 118, 11, 128, 217, 66, 146, 118, 52, 69, 179, 230, 1, 234, 39, 30, 61, 230, 196, 95, 116, 18, 144, 0, 46, 22, 186, 136, 96, 0, 0, 1, 10, 17}) + + tv5.Exp(tv5, &exp) // 6. tv5 = tv5ᶜ³ + tv5.Mul(&tv5, &tv2) // 7. tv5 = tv5 * tv2 + tv2.Mul(&tv5, v) // 8. tv2 = tv5 * v + tv3.Mul(&tv5, u) // 9. tv3 = tv5 * u + tv4.Mul(&tv3, &tv2) // 10. tv4 = tv3 * tv2 + + // c5 = 35184372088832 + exp.SetBytes([]byte{32, 0, 0, 0, 0, 0}) + tv5.Exp(tv4, &exp) // 11. tv5 = tv4ᶜ⁵ + isQNr := g1NotOne(&tv5) // 12. isQR = tv5 == 1 + c7 := fp.Element{13262060633605929793, 16269117706405780335, 1787999441809606207, 11078968899094441280, 17534011895423012165, 96686002316065324} + tv2.Mul(&tv3, &c7) // 13. tv2 = tv3 * c7 + tv5.Mul(&tv4, &tv1) // 14. tv5 = tv4 * tv1 + tv3.Select(int(isQNr), &tv3, &tv2) // 15. tv3 = CMOV(tv2, tv3, isQR) + tv4.Select(int(isQNr), &tv4, &tv5) // 16. tv4 = CMOV(tv5, tv4, isQR) + exp.Lsh(big.NewInt(1), 46-2) // 18, 19: tv5 = 2ⁱ⁻² for i = c1 + + for i := 46; i >= 2; i-- { // 17. for i in (c1, c1 - 1, ..., 2): + + tv5.Exp(tv4, &exp) // 20. tv5 = tv4ᵗᵛ⁵ + nE1 := g1NotOne(&tv5) // 21. e1 = tv5 == 1 + tv2.Mul(&tv3, &tv1) // 22. tv2 = tv3 * tv1 + tv1.Mul(&tv1, &tv1) // 23. tv1 = tv1 * tv1 Why not write square? + tv5.Mul(&tv4, &tv1) // 24. tv5 = tv4 * tv1 + tv3.Select(int(nE1), &tv3, &tv2) // 25. tv3 = CMOV(tv2, tv3, e1) + tv4.Select(int(nE1), &tv4, &tv5) // 26. tv4 = CMOV(tv5, tv4, e1) + + if i > 2 { + exp.Rsh(&exp, 1) // 18, 19. tv5 = 2ⁱ⁻² + } + } + + *z = tv3 + return isQNr +} + +func g1NotOne(x *fp.Element) uint64 { + + var one fp.Element + return one.SetOne().NotEqual(x) + +} + +// g1MulByZ multiplies x by [5] and stores the result in z +func g1MulByZ(z *fp.Element, x *fp.Element) { + + res := *x + + res.Double(&res) + res.Double(&res) + res.Add(&res, x) + + *z = res +} + +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method +// MapToCurve1 implements the SSWU map +// No cofactor clearing or isogeny +func MapToCurve1(u *fp.Element) G1Affine { + + var sswuIsoCurveCoeffA = fp.Element{17252667382019449424, 8408110001211059699, 18415587021986261264, 10797086888535946954, 9462758283094809199, 54995354010328751} + var sswuIsoCurveCoeffB = fp.Element{11130294635325289193, 6502679372128844082, 15863297759487624914, 16270683149854112145, 3560014356538878812, 27923742146399959} + + var tv1 fp.Element + tv1.Square(u) // 1. tv1 = u² + + //mul tv1 by Z + g1MulByZ(&tv1, &tv1) // 2. tv1 = Z * tv1 + + var tv2 fp.Element + tv2.Square(&tv1) // 3. tv2 = tv1² + tv2.Add(&tv2, &tv1) // 4. tv2 = tv2 + tv1 + + var tv3 fp.Element + var tv4 fp.Element + tv4.SetOne() + tv3.Add(&tv2, &tv4) // 5. tv3 = tv2 + 1 + tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6. tv3 = B * tv3 + + tv2NZero := g1NotZero(&tv2) + + // tv4 = Z + tv4 = fp.Element{9871116327010172167, 9167007004823125620, 18338974479346628539, 5649234265355377548, 13442091487463296847, 77904398905292312} + + tv2.Neg(&tv2) + tv4.Select(int(tv2NZero), &tv4, &tv2) // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + tv4.Mul(&tv4, &sswuIsoCurveCoeffA) // 8. tv4 = A * tv4 + + tv2.Square(&tv3) // 9. tv2 = tv3² + + var tv6 fp.Element + tv6.Square(&tv4) // 10. tv6 = tv4² + + var tv5 fp.Element + tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6 + + tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5 + tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3 + tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4 + + tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6 + tv2.Add(&tv2, &tv5) // 16. tv2 = tv2 + tv5 + + var x fp.Element + x.Mul(&tv1, &tv3) // 17. x = tv1 * tv3 + + var y1 fp.Element + gx1NSquare := g1SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + + var y fp.Element + y.Mul(&tv1, u) // 19. y = tv1 * u + + y.Mul(&y, &y1) // 20. y = y * y1 + + x.Select(int(gx1NSquare), &tv3, &x) // 21. x = CMOV(x, tv3, is_gx1_square) + y.Select(int(gx1NSquare), &y1, &y) // 22. y = CMOV(y, y1, is_gx1_square) + + y1.Neg(&y) + y.Select(int(g1Sgn0(u)^g1Sgn0(&y)), &y, &y1) + + // 23. e1 = sgn0(u) == sgn0(y) + // 24. y = CMOV(-y, y, e1) + + x.Div(&x, &tv4) // 25. x = x / tv4 + + return G1Affine{x, y} +} + +func g1EvalPolynomial(z *fp.Element, monic bool, coefficients []fp.Element, x *fp.Element) { + dst := coefficients[len(coefficients)-1] + + if monic { + dst.Add(&dst, x) + } + + for i := len(coefficients) - 2; i >= 0; i-- { + dst.Mul(&dst, x) + dst.Add(&dst, &coefficients[i]) + } + + z.Set(&dst) +} + +// g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields +// Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function +// The sign of an element is not obviously related to that of its Montgomery form +func g1Sgn0(z *fp.Element) uint64 { + + nonMont := z.Bits() + + // m == 1 + return nonMont[0] % 2 + +} + +// MapToG1 invokes the SSWU map, and guarantees that the result is in g1 +func MapToG1(u fp.Element) G1Affine { + res := MapToCurve1(&u) + //this is in an isogenous curve + g1Isogeny(&res) + res.ClearCofactor(&res) + return res +} + +// EncodeToG1 hashes a message to a point on the G1 curve using the SSWU map. +// It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func EncodeToG1(msg, dst []byte) (G1Affine, error) { + + var res G1Affine + u, err := fp.Hash(msg, dst, 1) + if err != nil { + return res, err + } + + res = MapToCurve1(&u[0]) + + //this is in an isogenous curve + g1Isogeny(&res) + res.ClearCofactor(&res) + return res, nil +} + +// HashToG1 hashes a message to a point on the G1 curve using the SSWU map. +// Slower than EncodeToG1, but usable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func HashToG1(msg, dst []byte) (G1Affine, error) { + u, err := fp.Hash(msg, dst, 2*1) + if err != nil { + return G1Affine{}, err + } + + Q0 := MapToCurve1(&u[0]) + Q1 := MapToCurve1(&u[1]) + + //TODO (perf): Add in E' first, then apply isogeny + g1Isogeny(&Q0) + g1Isogeny(&Q1) + + var _Q0, _Q1 G1Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1).AddAssign(&_Q0) + + _Q1.ClearCofactor(&_Q1) + + Q1.FromJacobian(&_Q1) + return Q1, nil +} + +func g1NotZero(x *fp.Element) uint64 { + + return x[0] | x[1] | x[2] | x[3] | x[4] | x[5] + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g2.go new file mode 100644 index 00000000000..66aae9fcc79 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/hash_to_g2.go @@ -0,0 +1,809 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" + + "math/big" +) + +//Note: This only works for simple extensions + +func g2IsogenyXNumerator(dst *fptower.E2, x *fptower.E2) { + g2EvalPolynomial(dst, + false, + []fptower.E2{ + { + A0: fp.Element{3551783286045471771, 15672698349814166255, 7201714524012399751, 9685135133462022557, 11459791422433132438, 34279211894444158}, + A1: fp.Element{6733784119909728882, 8027365598504339614, 9826395261252013434, 17766961605401961078, 16718790361550578585, 8827310132881948}, + }, + { + A0: fp.Element{10039326048219096853, 8025585753053690704, 15692757884719051200, 14081267914923412694, 12483400733579637594, 41501995942887693}, + A1: fp.Element{3285050121746765179, 16424976010740556635, 13525960835401060630, 8230390587856081588, 332312595686915068, 58693565636984574}, + }, + { + A0: fp.Element{17569899329826403508, 9637548884483664645, 11559603533194429416, 509473447889017775, 16843450937194425803, 11820413515158522}, + A1: fp.Element{18082143759519379917, 7350976797508953919, 8718515184478260262, 11424641547646470649, 12610734036362352161, 109931236078585740}, + }, + { + A0: fp.Element{14344095877598929896, 14770204065590636976, 13870643972022067464, 14327299415926938990, 2100218127689809229, 111985606372347998}, + A1: fp.Element{18166912950538149334, 7903342274102247275, 11235613814926762637, 6048582781848067329, 9865957781737849443, 72257053590751229}, + }, + { + A0: fp.Element{9289693438943775070, 611273684478921638, 3161020385710416475, 2286858861996231773, 14631078872284738786, 101751379483637100}, + A1: fp.Element{218371821390517888, 3239557307852648611, 7956123978234311251, 4433191957359481551, 7602230667186897987, 36183482319693410}, + }, + { + A0: fp.Element{7524026848147356443, 15899508093607509001, 9269755160329214834, 12526651159477248728, 3756002781809695765, 101164747683440023}, + A1: fp.Element{6220885675233469595, 1070578225745722143, 9028649589122227273, 241265531361573072, 17722097355684345537, 59426317598728635}, + }, + { + A0: fp.Element{1147337684740884862, 11995598217907408439, 6334092051568104396, 4490620767408292574, 16484486820571077628, 32056264099725884}, + A1: fp.Element{1626504798254052117, 15843967556282260399, 3222912561813979091, 1092398256542226755, 15613117580878270463, 35759440311789519}, + }, + { + A0: fp.Element{9456818710433496904, 8738575976265225627, 17481785322204872502, 10252666647792359788, 13007033241788380867, 54062177864773120}, + A1: fp.Element{7857657292788377886, 18159261954362575139, 6957043223229770024, 101887390030524213, 7411469664095682342, 17462521019270966}, + }, + { + A0: fp.Element{5935437080311313022, 4869272223104979307, 14892623520420170949, 6274040211921387638, 190450687675494048, 100326942952217018}, + A1: fp.Element{4080141112519796596, 14389619698824585061, 15572076811388758383, 5573262239497616930, 5714216936392065098, 10910945353280475}, + }, + { + A0: fp.Element{12050383421129197508, 7679000367015579641, 4181895471589351098, 4488864303009131705, 1755297417051974713, 33780283701258651}, + A1: fp.Element{11393221592097145268, 10835918896706663346, 4746287363995169177, 6169630568067228482, 11259555703140136465, 52771734216395635}, + }, + { + A0: fp.Element{4577617767559140265, 568504000295320317, 4739467389388831592, 9537638546299567945, 11669151734363428413, 119097732794758712}, + A1: fp.Element{5691235310984308451, 13601281267571106288, 7819292534586961743, 11652278682059157182, 2231701566242469994, 110966193728844398}, + }, + { + A0: fp.Element{8957158313166077105, 5669155713645675267, 17333896861619738764, 4892240835897020648, 8492829473755858526, 70767002641220602}, + A1: fp.Element{8355305174234995113, 16726408794609999189, 6819868380250046496, 9302398329327482182, 3371252083110614225, 32903157732774708}, + }, + { + A0: fp.Element{3562726361589542410, 15642076536163677636, 3828009540728039550, 5513538145598570884, 1202255355797680138, 19209968154720986}, + A1: fp.Element{2433342667414904247, 14430646666116795259, 7881503288178112304, 10086912537277758921, 14321155618236575013, 84224128485096326}, + }, + { + A0: fp.Element{7543845460144717594, 14101022520017632284, 6419288061290617259, 11326768478076341964, 18432026940412127132, 85359846879027793}, + A1: fp.Element{17142157839755119212, 5159976764710014065, 6393633352893279233, 8672509349035392886, 7859431465567482570, 62163334379266093}, + }, + { + A0: fp.Element{2954881934412060022, 10898916794193723070, 10915833338735408379, 703491535562714344, 14589964434689495439, 90051679935520087}, + A1: fp.Element{18417998714611085978, 11039054240270137506, 9972891257774348246, 13263552626589315210, 4522668809484918556, 63885995997825101}, + }, + { + A0: fp.Element{9864134077459603571, 12525567282624341376, 5205345924937688700, 12649124091757575439, 14636003906379491067, 96025183135833306}, + A1: fp.Element{10316403063861314867, 10750711173072110600, 4513675589861596212, 2635673197095740125, 16720951430549947037, 31390298180493148}, + }, + { + A0: fp.Element{3003952238586646516, 3250841642932517220, 7061834734009117554, 16259415476002355236, 1626926148029432162, 77189086665928784}, + A1: fp.Element{14450051585993059472, 11823315281584113748, 6929304997500454604, 15344892292748160673, 15787768514545706202, 69813057053620435}, + }, + { + A0: fp.Element{4228110392233474072, 18010581486575392207, 13699345898545483049, 17704744337446085874, 5487913134051621310, 112205105149111207}, + A1: fp.Element{14824585485470590037, 7637124239293942071, 1041102438278370701, 4207950142422409777, 9639439542389544094, 106832755917361143}, + }, + { + A0: fp.Element{10744145886747796703, 8741979218876153119, 4537642647264646058, 9645243825719833866, 16643801652280184094, 57528843479739428}, + A1: fp.Element{5785935421797206370, 847985697064985249, 11478142027129258160, 12741057482356268413, 10148591557028647803, 106797667835022069}, + }, + { + A0: fp.Element{6454832842704992412, 9977685523482313420, 413111938383295655, 13594952949000658414, 17807487788385728582, 108984464456649540}, + A1: fp.Element{17048359867690489456, 2859252502285541521, 10818623701995947153, 7550564651763690537, 459333235977057482, 37663478480017988}, + }, + { + A0: fp.Element{8658783637463168087, 13532094408327228336, 12875492560745818922, 6809856611120372218, 2853890452345629690, 87034840621524077}, + A1: fp.Element{16301307707120111515, 9104654412985804807, 12475785366789695268, 4024450921325678435, 5626908908910088752, 56687303925216568}, + }, + { + A0: fp.Element{9729408098285946449, 14379177692720606450, 15077053755146607368, 1299576162980711320, 13990524355831736308, 88070216003513722}, + A1: fp.Element{5766436769337206504, 1093294963802231624, 1118315683159380206, 16238633443172785277, 5463682062430385614, 116508026946667814}, + }, + { + A0: fp.Element{16584249698770136319, 8326278446225484560, 3131917383401484830, 4756633391835977312, 7642636045510739113, 6547192373501023}, + A1: fp.Element{10803045440816594384, 6133821182275761752, 7762705812675926549, 15035799326051880159, 10201360843527298396, 76693252438359195}, + }, + { + A0: fp.Element{3621702609341817994, 1179514540952803843, 9695126383219869545, 4861853798003230532, 15648444733987506481, 103088924877589738}, + A1: fp.Element{0}, + }, + }, + x) +} + +func g2IsogenyXDenominator(dst *fptower.E2, x *fptower.E2) { + g2EvalPolynomial(dst, + true, + []fptower.E2{ + { + A0: fp.Element{1063048776114699222, 13419136991291290443, 17670140655952814712, 17007170270485437006, 2714055472280753035, 14919040757258909}, + A1: fp.Element{16666868668043867029, 10413023948165423527, 2513282340300795191, 5135056029366772344, 18074639060500180041, 66260525510488187}, + }, + { + A0: fp.Element{10940415603117103310, 2845175453419864190, 16971099885047235913, 4517542951822462583, 12015180195047358700, 101962474939260879}, + A1: fp.Element{1812172074217037271, 9040376510937171745, 1548369375982775200, 5323713323104515663, 11625954855074087334, 4220230277540083}, + }, + { + A0: fp.Element{8797262280793960976, 17802450974932240081, 10157003283304584770, 593225980605733121, 14184353532500093055, 108979035901112461}, + A1: fp.Element{15554837140147424903, 1512405638789788986, 3262333938884419786, 4638305243452530609, 139542405126620667, 54024907639584882}, + }, + { + A0: fp.Element{11424716963860540790, 13456329776215064369, 1929697779149270213, 6306593112502705131, 13859057472975507250, 41785102954052035}, + A1: fp.Element{7602541488494927932, 4897344463908346766, 17005994653424089316, 17216735712046963938, 3756018940504096168, 5402674048264985}, + }, + { + A0: fp.Element{2416535722849524790, 4831233808757576698, 17297774284520319797, 6772473332127607735, 18174962172090050489, 58994994344686536}, + A1: fp.Element{15610410799617712282, 9543692017702705957, 8970286522052539731, 12714219237879632746, 2449975609997710437, 10121059733973512}, + }, + { + A0: fp.Element{15388608950644940213, 15178518612850901922, 4663566445208062329, 3999751164791233677, 7358895960008222342, 33044898311505685}, + A1: fp.Element{2356569524239497521, 4634121806982763800, 13294827248503187097, 18379906191200424608, 13949207972645393879, 37350653623873291}, + }, + { + A0: fp.Element{4970487283568561993, 8451944303783250587, 10744185545939488302, 297910826254460501, 5663064319185246782, 55864728573479562}, + A1: fp.Element{13676619861655804765, 9740179349809417716, 1447466405783296044, 7262347140551810932, 4460517809397706328, 48696693541469882}, + }, + { + A0: fp.Element{4218670501850515232, 1300837062036343562, 6322288902222626865, 2517640049285419442, 15933997662514683752, 35742655751559900}, + A1: fp.Element{8671399843829082486, 10727571055999201132, 18066412728811459184, 2077243532292929295, 18402906919639961112, 11053564656556137}, + }, + { + A0: fp.Element{13549293427847064273, 13454861990004702789, 12625716182603551974, 16289223817658875114, 709786698748164395, 79373748066056979}, + A1: fp.Element{9755261456181601166, 8062867867952015070, 11667298511884909423, 12783693965971962594, 5335701901003645771, 118924945769569072}, + }, + { + A0: fp.Element{5024330816113629597, 9162185537450801251, 14637535063833510048, 5042964231794706299, 10987285991634226322, 46336617111585333}, + A1: fp.Element{17451698037621354790, 10238258568486351103, 10306732172443683782, 16783673474705190959, 2366024509224094980, 27102949281362657}, + }, + { + A0: fp.Element{1779719694787807439, 13682444363499832102, 319805876265464201, 10878143779945294209, 5260570358490406259, 111384964548942529}, + A1: fp.Element{10364815279125342799, 5955681787042171859, 16259776976357711022, 698420282628335564, 14458917752432688041, 9951241155641633}, + }, + { + A0: fp.Element{9860169129499874274, 4710132861939245083, 16729683163954203081, 1163919786098698325, 16999533791398931846, 45007426249965870}, + A1: fp.Element{1554156753268998897, 13001788039766734041, 13083055690099472212, 15457335577166095794, 9225717367159961098, 40091861438122274}, + }, + { + A0: fp.Element{15170394446649694794, 515688257282406708, 7546053921359572147, 2040402108618036352, 14910633907967741865, 51620635462170312}, + A1: fp.Element{14097816726424606264, 12505549891408832791, 13993079436736795338, 10172463092702817360, 608991345474995671, 70034669163571313}, + }, + { + A0: fp.Element{4643108199199003526, 15736620484932148216, 15681664113334307244, 17299685843716562967, 13906356132799386736, 93346316071232156}, + A1: fp.Element{4605618257264761423, 18021103018327472901, 16108946406338519358, 9045268489748282166, 5059321869053749600, 110536556169650965}, + }, + { + A0: fp.Element{11517108407780568371, 7978619811691229504, 9264608640258152436, 8451802924690124465, 4675285626878377699, 109463398958344863}, + A1: fp.Element{3597960821476001565, 3759680844169152876, 14302414818654496990, 17433096654117785124, 17967041042193057544, 85366167313641495}, + }, + { + A0: fp.Element{9939822412604413185, 13452127979624463736, 5130248585009642508, 3885932386715663181, 5051687816649505884, 77901780572240613}, + A1: fp.Element{519763984047258436, 9600915485628319569, 15140529797299450996, 9971542775239334883, 8807015558507490608, 948222705021672}, + }, + { + A0: fp.Element{2827339587428175511, 6895834130469522434, 13331059522798479027, 13955187059915735579, 14378880524037078149, 37849146151734053}, + A1: fp.Element{5659129353366385472, 1315670479643534676, 5263307416551198333, 6925817959331280727, 2077163856293267360, 78059303625906606}, + }, + { + A0: fp.Element{12063007979636530410, 11856928215255593909, 11875394835884852884, 7779285203935234969, 6621016507099994054, 58081312732574672}, + A1: fp.Element{16883486087598545310, 13020319043706888256, 13790070886127375971, 1584348143126996741, 14269751476430075034, 39520851290632316}, + }, + { + A0: fp.Element{10496651096160116529, 17447330314090714314, 7901980568892205616, 12523643767284114259, 14047697587913173436, 75967257029771325}, + A1: fp.Element{928850053641029162, 14269106311960337185, 16222409674828338261, 5805191570224440459, 18405225593952050465, 81611267238126250}, + }, + { + A0: fp.Element{11963245856892367752, 10425756598646938656, 18335238837348744770, 15086772981218061512, 16514870314421827966, 31505685309500160}, + A1: fp.Element{12503518650914401765, 9253053408485518576, 7574198415595259890, 9578781703355827570, 4997060354564847196, 4129967821132897}, + }, + { + A0: fp.Element{2031421031641935199, 11357963626711833272, 3216176135850906142, 18356175605205399499, 14930266308542898024, 45166487627178747}, + A1: fp.Element{4224679465464892278, 5162816687557914011, 9625001313214472999, 9646089844316603379, 3042432097393437616, 116654205222221531}, + }, + { + A0: fp.Element{707631102761073363, 4675040476129639901, 7917747947488915690, 10109499984363985170, 8993410474198507338, 72712009800189820}, + A1: fp.Element{13149412355826661761, 13738163990683470943, 2035497293527985654, 18119267602401018212, 2631647798265895027, 2795783216290358}, + }, + }, + x) +} + +func g2IsogenyYNumerator(dst *fptower.E2, x *fptower.E2, y *fptower.E2) { + var _dst fptower.E2 + g2EvalPolynomial(&_dst, + false, + []fptower.E2{ + { + A0: fp.Element{17926225976816550695, 14023720841551579195, 6357178813752170559, 1429363592569423041, 10398153225153858948, 33711798988254397}, + A1: fp.Element{2451854115792992988, 8983506616720050336, 2910564589437158732, 14075622914381394491, 9210830493684175792, 3356683084380210}, + }, + { + A0: fp.Element{5363401642911389912, 1675875184098052872, 15320530934239994732, 16287584047609698426, 10234580471621189795, 40152057551620421}, + A1: fp.Element{2205557896318444105, 4065007897235623968, 4049591920488634456, 16004168804099107709, 13290522222905374988, 70089339901218536}, + }, + { + A0: fp.Element{1887285394871164447, 7142690945990485012, 11190732658400833066, 6881717282640585612, 12116088968278807379, 103071704289665226}, + A1: fp.Element{15968649428224979513, 622837296484333259, 15527184444320989860, 2221190225062639140, 16647213690505955661, 110449865605275384}, + }, + { + A0: fp.Element{8732294600695513394, 7924365878303510912, 12588020556237861366, 10068029016225118132, 785053188876688927, 120347068207419939}, + A1: fp.Element{14514622768737464893, 5553264648606662629, 12707457796658055665, 6066303778837734141, 8279024849745683367, 3564406469625657}, + }, + { + A0: fp.Element{10035254538193759291, 9758866910217654439, 2724217928072676653, 3087232989313988901, 14980280964270815877, 34590022796322467}, + A1: fp.Element{15702474365778911803, 7256912742043165018, 1566344877835261304, 4035729625101537726, 16346625826270990512, 84087754076446931}, + }, + { + A0: fp.Element{8353555275402615800, 6017666668033757053, 13076202439893933084, 1913164921831891521, 13296563472388407395, 43485447354470561}, + A1: fp.Element{12571296156797641372, 13988198528186614994, 5672291450663514913, 7033607850615758657, 16846880911077910300, 44471894806759326}, + }, + { + A0: fp.Element{1319289899879823718, 1591088360172441240, 7805677496653365276, 5569897284498525554, 5635591756513279404, 74901024143303203}, + A1: fp.Element{10251017843654697682, 10395107644570958416, 3071938417266745181, 16127666859700570668, 5111665418914357408, 2168588371926498}, + }, + { + A0: fp.Element{7692831217085618076, 6702179445852008930, 11308520252707392151, 12038365346701529390, 7201289518723110646, 24757234241788495}, + A1: fp.Element{17948859968330001914, 10144279887227452625, 5167544611537672341, 4094514978127885079, 17912079766649616973, 45691468580901020}, + }, + { + A0: fp.Element{3911440855998194160, 13198838254872822648, 13301641437413064797, 11598620320741753383, 6260523097595092689, 78284230929812985}, + A1: fp.Element{7876366075466990529, 13523468790275433139, 982512625724968021, 2122595334378906057, 14803785928219626498, 71415583741911053}, + }, + { + A0: fp.Element{14923926944529083273, 3172840012894527710, 8293434476071337387, 16713256045335958267, 14057165773167995662, 57626475506313562}, + A1: fp.Element{1362417042314121750, 3304417561071796103, 17626406775105189491, 11748219015558348173, 14151421547261463616, 82460535821434588}, + }, + { + A0: fp.Element{3641967463568066103, 8959416625663108732, 5147508997828480363, 16811352377666989046, 1441182181356889676, 52012247235371457}, + A1: fp.Element{17686146190561162997, 11457769513035421935, 11629039572857129752, 16013548565551254584, 3489389447040062088, 108111902919606578}, + }, + { + A0: fp.Element{3810472718885394006, 2981020169366520013, 2816385682378197235, 153866317221550159, 11847618666936524337, 45551005605881971}, + A1: fp.Element{3468095351662354134, 4642197759139584052, 4233923780028877603, 17495173774535575422, 6042084483130094534, 67695926977382460}, + }, + { + A0: fp.Element{1324953063484934482, 15924484690572898301, 11397027945012096698, 2650928770069584769, 15779309286157100138, 107280353846472153}, + A1: fp.Element{7825813464319090460, 9031312139767459777, 142189155675192148, 6582610291000324889, 17102396003811978688, 22084094988625284}, + }, + { + A0: fp.Element{5210064249141309135, 1705543797894948713, 2628665872375881350, 13536211673960271710, 18420806283098729881, 115824256193502087}, + A1: fp.Element{15082907751180860242, 6568697878451242210, 16244491021091296231, 17790448340613041754, 7733097786923840729, 14504831353209381}, + }, + { + A0: fp.Element{1708526764431582271, 13958279355051552323, 14990211071762970223, 7884242526085975541, 16332397605884981291, 80533848446738849}, + A1: fp.Element{14979957683309612745, 6077136825354362762, 8344075647158254715, 10162044015152162839, 5892600246835629906, 87516868768986919}, + }, + { + A0: fp.Element{13823384149985104375, 400062563487168190, 14946453239900597346, 3063239780002983931, 12307299790663558215, 82575345472847758}, + A1: fp.Element{4955387593349539956, 11580263215419679285, 13810204272372323220, 15118104627613044122, 5709821153764726112, 97792497530186865}, + }, + { + A0: fp.Element{8029106480647627463, 9339835209992361362, 2257747803917390435, 13841766612482081060, 11846105036367819521, 10985089103756089}, + A1: fp.Element{12896564185217823813, 11446288085903243988, 7990576940036837900, 3323202217483830000, 8230734762253073878, 36590510406546600}, + }, + { + A0: fp.Element{9258620980666570289, 14799769271847025124, 3337623733744503313, 7847288847664005088, 4443979768963902018, 60018570132140318}, + A1: fp.Element{2675246192261018596, 15150250319428322656, 8044595947793549351, 17819017498503740634, 8168003399719773701, 50802205070212383}, + }, + { + A0: fp.Element{6416675551757596528, 11137110755893373387, 12196234615749865580, 10261229930898283794, 16443034629854739148, 92762661836396101}, + A1: fp.Element{2617757450501858457, 13481841765161333192, 14399351126797435540, 14845648777279341476, 16479218442290092360, 58694504406226241}, + }, + { + A0: fp.Element{2498292483400110656, 17577335584861186499, 17782334663901894811, 2829649086165738601, 1498570879458573752, 54126946483698861}, + A1: fp.Element{13664305368410221366, 15519373467383236285, 6930373704919785768, 5035259077705758702, 15118622066815350587, 76218461077450180}, + }, + { + A0: fp.Element{2359464294290896887, 15126005627433822176, 8745471049496239338, 16249169944251666409, 5887779353961924474, 9756279022859315}, + A1: fp.Element{4564346538121733135, 7083224900235365477, 12708889282498498077, 7850548098138279688, 14178174888234998222, 79663491154927524}, + }, + { + A0: fp.Element{2363371748841007386, 8201543480932182326, 3606722496785934427, 11335897361905574349, 7238564335142183540, 28370763379089425}, + A1: fp.Element{17773120842166679454, 6968817275085296949, 589078002303466881, 11901496965136831973, 17508389603594408067, 105726710734816064}, + }, + { + A0: fp.Element{7295712044514929446, 1419749005841863626, 15921158613862149232, 9464988326326595083, 4254037448365833139, 69144288462579473}, + A1: fp.Element{2330521880128496868, 6942731841460529291, 16753201799444057524, 5125438220420299042, 743707329901356982, 86418732453789215}, + }, + { + A0: fp.Element{10073672469351267894, 7530218602938011234, 12150950127635720924, 14699101300080070173, 3657462378365608060, 50677269975209252}, + A1: fp.Element{16217326474471800173, 12182932688121705224, 9523557196391803719, 13559107473982584173, 14264388955497449506, 89155196038187526}, + }, + { + A0: fp.Element{8500524953883552338, 13471246252006481381, 399342016929624192, 15321780621361720165, 1735807610194144505, 81584295376527434}, + A1: fp.Element{3028140852425956403, 9738549527114127103, 13145547273810927, 15439064114192138046, 15332022320720552951, 84308032823666865}, + }, + { + A0: fp.Element{8795699974103596314, 642987394252844125, 12559698238980671421, 15439596853334509309, 8192837603484177265, 86858193154220713}, + A1: fp.Element{13665577425741482529, 6924526015867702055, 8773433633434605845, 4385776193759960181, 14751123844375383386, 84259094466106596}, + }, + { + A0: fp.Element{6308743764871173820, 14529376135552483358, 3992864522868188832, 16018150786687814926, 14942376479240309869, 30721880050281254}, + A1: fp.Element{8640235552523037016, 9835096537876469025, 789797926152341591, 17554386444425767744, 2184317346571194421, 105569965705365467}, + }, + { + A0: fp.Element{10895141504918788686, 5671269070898752172, 9721970862384110947, 6958416614840799556, 18087813302866953828, 120526621462965167}, + A1: fp.Element{4966785024859028542, 18182687130036955400, 10092534947477547130, 11367367723010839926, 7417818378683193783, 94369912047147779}, + }, + { + A0: fp.Element{5709922971951703245, 10382852257937442526, 3453842328747730539, 16133368957829378910, 8271517063962590774, 9539719803485949}, + A1: fp.Element{1704900793320796784, 8995901783485359023, 9994857694012530400, 7408202244508772902, 18055801701001909838, 109149704128086904}, + }, + { + A0: fp.Element{8357460663115985094, 5765296628618444602, 6421674075164890879, 1651079036919805888, 1287520506307076832, 98975482931648514}, + A1: fp.Element{8078944849704442787, 4038716179863104913, 8864619430523621449, 11983583689047803099, 2541042365160408900, 28281336919305267}, + }, + { + A0: fp.Element{13472601104608613638, 521231156844377864, 4649313698209759510, 5796371833735044995, 8684999192663632207, 51033152603009675}, + A1: fp.Element{3409558318672010377, 10145443448574304058, 3995874611835909177, 15021984820089990008, 15242143999191686238, 73656911605031936}, + }, + { + A0: fp.Element{9770462122700591808, 17547477902406858790, 14010124614813851222, 4165622522809648336, 16982670942141592785, 28856170353703120}, + A1: fp.Element{15290128055618535720, 17454664547186830394, 2442682438806360163, 18129275600450347134, 4187898517238597724, 22281223126461925}, + }, + { + A0: fp.Element{12998303454550796060, 5752293956714303316, 6752814987597331313, 3166668351495264669, 9929418606104908953, 29385282975911842}, + A1: fp.Element{8756413506556179286, 143408982899135549, 2705277708630136288, 5154523209628123430, 6318572504564936509, 15532021916109921}, + }, + { + A0: fp.Element{18250508560718013179, 7486164413457419330, 8732750857092323232, 457033717118918321, 12167888022606617966, 20277559260742340}, + A1: fp.Element{0}, + }, + }, + x) + + dst.Mul(&_dst, y) +} + +func g2IsogenyYDenominator(dst *fptower.E2, x *fptower.E2) { + g2EvalPolynomial(dst, + true, + []fptower.E2{ + { + A0: fp.Element{2775408832476871526, 9008699192344519496, 1102884431771657931, 11532306452895462867, 5856674524343862704, 99430919144638985}, + A1: fp.Element{15551301223123894338, 11614654532478001117, 17328204268627498271, 15544698294678786409, 1484472732893154418, 94605104690421825}, + }, + { + A0: fp.Element{15538486723908094425, 10978766348102143722, 15056964343960721360, 8732109610906448146, 8620899699042055528, 1351681984895437}, + A1: fp.Element{3175104032835843731, 9314571151837830613, 14059118678096680542, 2500500275627160283, 18190796245603721369, 49058560079762280}, + }, + { + A0: fp.Element{2177050294381443304, 18124514285214412099, 9381797198372716589, 8046190315005422985, 9931273159159670369, 8036418831901820}, + A1: fp.Element{1549742439238596983, 15619417821567290543, 9431498181016104480, 2850048082163302555, 17545915875775834651, 72687252788290726}, + }, + { + A0: fp.Element{16572119218800158686, 13113809656757589233, 12872678318679566545, 3255385198038960565, 17070551903094984362, 19742086936927308}, + A1: fp.Element{12635717383520653743, 12204869003999147728, 8256611698395114158, 12382254302890131233, 603685913325391887, 60927550204070150}, + }, + { + A0: fp.Element{15497795759006280655, 16847324196958114585, 8218328297664216257, 15353718428023978640, 6357440186573265200, 109435672289072692}, + A1: fp.Element{17126430308003109280, 8510055147921463837, 2424009275722614739, 9284383313721206596, 12867548350984534889, 46750493171897961}, + }, + { + A0: fp.Element{6993808529266055670, 10024278910497662817, 6638820395273369627, 17550512930522052164, 11971278025880956390, 4218694435301565}, + A1: fp.Element{4117072311900938869, 8052759146924035127, 1883914237959498468, 843437547616490150, 1332392274725871932, 100467415201018114}, + }, + { + A0: fp.Element{10031273074038578964, 6635740043384123318, 2357760728051263554, 12405057037224522557, 2967360385882286162, 53130165628915609}, + A1: fp.Element{9340276074750471546, 8779557686584984578, 12118682911992514942, 8792287004994786286, 11729922744948342197, 97115621599174349}, + }, + { + A0: fp.Element{8243258075199662251, 789646305137795307, 9501755430432007632, 15339245131080115010, 3036491630055907252, 4720358405852701}, + A1: fp.Element{6272873484523042114, 18180794113363272037, 10135093694274252446, 13006427779172872075, 12612518697452888675, 4088970499189038}, + }, + { + A0: fp.Element{12559327402496405011, 13162954855686166920, 2622361684062280170, 16985128559432625018, 10671934355632922492, 22106668982430516}, + A1: fp.Element{10342048742210368049, 4070662490021521195, 9050590024293164750, 6778744574336170333, 16385669267342466637, 110676722503289309}, + }, + { + A0: fp.Element{8257142434361782318, 11625188549524762434, 4162174183904813140, 15534648919830235837, 15345786270187761745, 49274740272907617}, + A1: fp.Element{17452699565973497082, 1589725784862892127, 17590303103109791779, 8233530623701537904, 717929863606521126, 42679722481449639}, + }, + { + A0: fp.Element{17135289411523873787, 11725292909156152853, 16347014946116696110, 13323937426977246609, 8703182288833044255, 99079409785168386}, + A1: fp.Element{9130446173903866415, 12010725389601806440, 9146179391205715125, 12338366065383252573, 9136251064810045627, 19315728226188373}, + }, + { + A0: fp.Element{13754907156191096138, 22846764546901886, 362622052532339515, 17013010775786408901, 13860043181928645305, 41171875858186406}, + A1: fp.Element{16141340011263075417, 18360728019638818576, 16264128300543356196, 12473458415555386384, 18336837302801391285, 63727493440743041}, + }, + { + A0: fp.Element{3658804449581456923, 1347747705877184398, 3978302900333357541, 5081865331785059868, 1329643100050532471, 64102076251113639}, + A1: fp.Element{6980160750786278877, 11782099681251246419, 5400025369843657828, 9848695260591786723, 7987487093370334558, 27115517650078156}, + }, + { + A0: fp.Element{408044901411159465, 18068234941175928745, 2992890619264445487, 8810813216534328625, 4005157550725594837, 26065038549738560}, + A1: fp.Element{10975300981822504330, 15715038812214651197, 7602692888794350386, 12917547374269268270, 422938878523833779, 36305463980543648}, + }, + { + A0: fp.Element{10382180122959422967, 15807168734599653808, 18372044240449882372, 17642941170379477011, 10340644338271517361, 36063527972088465}, + A1: fp.Element{17969075460977832752, 9177853432360197657, 2917850475625504299, 7079850467696515295, 787036529903063845, 107077168732108508}, + }, + { + A0: fp.Element{6502963492633373835, 9890663567118850708, 12445720805224431135, 6172862156806685987, 16576315346783950860, 5856337016358393}, + A1: fp.Element{4476660199518722374, 3771101137683024451, 489075951782192448, 6489873046594013732, 280944977367484653, 69709094171715534}, + }, + { + A0: fp.Element{5629815848909521275, 5316587566230943622, 7982019375390215350, 15543803108203970386, 5941855484214597918, 5142365312974746}, + A1: fp.Element{3442509802156923890, 6170315030905476396, 2122926024914179804, 17368567939581660282, 12200117156652989113, 7492215668086454}, + }, + { + A0: fp.Element{15017092692882720799, 2306085001940265068, 6863750251390498522, 772425548835188093, 7866794496176459304, 119478713276832042}, + A1: fp.Element{539473290914229032, 10680532665300974652, 2401493774971219183, 771791041055281045, 17266300769954562072, 46203199265737132}, + }, + { + A0: fp.Element{12080185159744170157, 6121786867780957883, 13378966825252880343, 16978399570563241468, 13189121794372052505, 31306179382417939}, + A1: fp.Element{6033582013845463960, 10201637616554513673, 3729832524646428556, 2564427389283182369, 662893124657004215, 101996692818942248}, + }, + { + A0: fp.Element{14864583376459179927, 16267452113314442715, 14135040057928255187, 712462212063179204, 12089188474131830930, 36841165809084721}, + A1: fp.Element{13089068048776542239, 1568107234484844315, 4262841373517201534, 572974140393742986, 13114372614372436015, 221271375458892}, + }, + { + A0: fp.Element{15352358256255559128, 14776149476170502093, 13834021062045579807, 16108249515581661111, 7563707564996631205, 86582638494403858}, + A1: fp.Element{16813570010660423536, 3065722476932153407, 8938713923763210470, 2255995557158728394, 8016474455897300271, 84052925693202818}, + }, + { + A0: fp.Element{15615825726181497195, 5658715128964929728, 13877560309241249627, 15409847795806183219, 382506108092986341, 33112756833083889}, + A1: fp.Element{4921115267284233431, 2093038862301396370, 11859221373400371788, 14840702906540650688, 3187022540654844811, 12940014803022939}, + }, + { + A0: fp.Element{10653597201928750109, 13006094245282229535, 13295987796930539448, 16777781019019743602, 516306931828031556, 114717773318043797}, + A1: fp.Element{235309942988776203, 14860563794932685398, 4559874204394395321, 16639699308077583607, 9227151754747780541, 15908917446924874}, + }, + { + A0: fp.Element{17337820088369903748, 8586614709689721762, 1507576901396006569, 12700849903501888588, 17971589925911161601, 108264042385722694}, + A1: fp.Element{16945398252920060844, 12661842631743740793, 3757011696927843364, 15267617233875676717, 4747339870779259550, 34661428542359791}, + }, + { + A0: fp.Element{16466466374773138846, 14279763770124955377, 2253148650834359538, 7990858085823320889, 7124676177871440280, 94151727797031734}, + A1: fp.Element{15321139925728056718, 15122461222407649886, 17533799169860262777, 16804941505997951982, 1600681788854461369, 44486672743339990}, + }, + { + A0: fp.Element{8867142699562737491, 18199028041645162481, 3517239929170429351, 775467166380995197, 5868381756625215392, 6197719424154602}, + A1: fp.Element{9737125075096738524, 9629792455358261596, 11564279494282885105, 5089237230157463720, 17189088638807565425, 106712839297101083}, + }, + { + A0: fp.Element{10270843696704620770, 13223598872017291793, 9010388952516938805, 15912131807459901749, 6846913031975448418, 86431140578472953}, + A1: fp.Element{15439335117817990542, 18208862128889198852, 1680174721576182500, 13180416124629130962, 7418066627384568449, 3653571306187636}, + }, + { + A0: fp.Element{1131060365675191416, 10374247235014096023, 5274169106847399340, 9643591707517384578, 8354961201546942085, 16860653124975415}, + A1: fp.Element{7591061314547569259, 3687653994280978709, 14906524746128876973, 7376139658567228596, 3304769414542873433, 39389809689964413}, + }, + { + A0: fp.Element{15061500520004024506, 13781868913987378153, 1311923405823490306, 13614698003779137726, 2734567429318555742, 41565578486180068}, + A1: fp.Element{2264606496492496938, 7463181801259856780, 4974231603582406689, 12631973597673125932, 13768142234619696863, 69859376569568629}, + }, + { + A0: fp.Element{12977806950220507699, 9598682745345891240, 12727041082031765282, 13876739454320532788, 16731345162096153922, 52377912619410421}, + A1: fp.Element{9749487977108607359, 9452745135768007871, 17734899000824388188, 6032906020241168466, 3891046964558379200, 42965172988847872}, + }, + { + A0: fp.Element{15134142718037669741, 2650609953202022541, 18444582952265559358, 10072051383647105272, 1614233522361858494, 6353896085976033}, + A1: fp.Element{1244819074686382314, 16827930012669440062, 7409202602064068605, 7833164804348414003, 14093967246945573989, 91886691830462491}, + }, + { + A0: fp.Element{3481568382353274479, 1454015438048276221, 18321294391133087854, 11721714833000613979, 10732204074831352562, 71241856315356756}, + A1: fp.Element{2091942538387325776, 9875355486415603002, 12623384858601965052, 7559030465493899268, 7674739998354242578, 75767137192853634}, + }, + { + A0: fp.Element{5491757234451068988, 6182298996664147147, 1538132785577256287, 4999224323735886804, 6348107227722746450, 48518858347037381}, + A1: fp.Element{15293807953430533698, 2990763629845967503, 13391735075948095730, 9673810945847290845, 11089480180973857099, 64742831177682886}, + }, + }, + x) +} + +func g2Isogeny(p *G2Affine) { + + den := make([]fptower.E2, 2) + + g2IsogenyYDenominator(&den[1], &p.X) + g2IsogenyXDenominator(&den[0], &p.X) + + g2IsogenyYNumerator(&p.Y, &p.X, &p.Y) + g2IsogenyXNumerator(&p.X, &p.X) + + den = fptower.BatchInvertE2(den) + + p.X.Mul(&p.X, &den[0]) + p.Y.Mul(&p.Y, &den[1]) +} + +// g2SqrtRatio computes the square root of u/v and returns 0 iff u/v was indeed a quadratic residue +// if not, we get sqrt(Z * u / v). Recall that Z is non-residue +// If v = 0, u/v is meaningless and the output is unspecified, without raising an error. +// The main idea is that since the computation of the square root involves taking large powers of u/v, the inversion of v can be avoided +func g2SqrtRatio(z *fptower.E2, u *fptower.E2, v *fptower.E2) uint64 { + + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-sqrt_ratio-for-any-field + + tv1 := fptower.E2{ + A0: fp.Element{0}, + A1: fp.Element{9669507733633691314, 13074846433352412541, 11948543988290594071, 11104573675215509690, 878729975203857826, 120237394476367878}, + } //tv1 = c6 + + var tv2, tv3, tv4, tv5 fptower.E2 + var exp big.Int + // c4 = 140737488355327 = 2⁴⁷ - 1 + // q is odd so c1 is at least 1. + exp.SetBytes([]byte{127, 255, 255, 255, 255, 255}) + + tv2.Exp(*v, &exp) // 2. tv2 = vᶜ⁴ + tv3.Square(&tv2) // 3. tv3 = tv2² + tv3.Mul(&tv3, v) // 4. tv3 = tv3 * v + tv5.Mul(u, &tv3) // 5. tv5 = u * tv3 + + // c3 = 237702427642072544657662731610863241996908072983433720914596829155825880635712864411696995402952020023758239370111403151139377997388748144480691770738487127695940799749981367718443673617185911789718419957467908625 + exp.SetBytes([]byte{2, 211, 7, 208, 187, 175, 251, 34, 86, 145, 59, 179, 97, 38, 60, 75, 184, 184, 125, 164, 174, 233, 63, 31, 94, 113, 65, 61, 218, 77, 92, 9, 208, 24, 175, 185, 6, 96, 205, 192, 20, 231, 18, 80, 42, 77, 108, 70, 10, 170, 170, 139, 183, 10, 224, 49, 131, 36, 185, 88, 99, 140, 157, 107, 203, 251, 210, 53, 241, 192, 154, 74, 218, 38, 143, 46, 27, 216, 0, 115, 56, 210, 84, 240, 0, 0, 1, 10, 17}) + + tv5.Exp(tv5, &exp) // 6. tv5 = tv5ᶜ³ + tv5.Mul(&tv5, &tv2) // 7. tv5 = tv5 * tv2 + tv2.Mul(&tv5, v) // 8. tv2 = tv5 * v + tv3.Mul(&tv5, u) // 9. tv3 = tv5 * u + tv4.Mul(&tv3, &tv2) // 10. tv4 = tv3 * tv2 + + // c5 = 70368744177664 + exp.SetBytes([]byte{64, 0, 0, 0, 0, 0}) + tv5.Exp(tv4, &exp) // 11. tv5 = tv4ᶜ⁵ + isQNr := g2NotOne(&tv5) // 12. isQR = tv5 == 1 + c7 := fptower.E2{ + A0: fp.Element{1479358275892676257, 2814264704614556731, 13691179386454739330, 7530671302001941842, 60362263363904715, 37906327945374822}, + A1: fp.Element{5350190547200862053, 10822704806123199611, 5122684409451163826, 10616884767534481491, 1436196917100294910, 20226740120672211}, + } + tv2.Mul(&tv3, &c7) // 13. tv2 = tv3 * c7 + tv5.Mul(&tv4, &tv1) // 14. tv5 = tv4 * tv1 + tv3.Select(int(isQNr), &tv3, &tv2) // 15. tv3 = CMOV(tv2, tv3, isQR) + tv4.Select(int(isQNr), &tv4, &tv5) // 16. tv4 = CMOV(tv5, tv4, isQR) + exp.Lsh(big.NewInt(1), 47-2) // 18, 19: tv5 = 2ⁱ⁻² for i = c1 + + for i := 47; i >= 2; i-- { // 17. for i in (c1, c1 - 1, ..., 2): + + tv5.Exp(tv4, &exp) // 20. tv5 = tv4ᵗᵛ⁵ + nE1 := g2NotOne(&tv5) // 21. e1 = tv5 == 1 + tv2.Mul(&tv3, &tv1) // 22. tv2 = tv3 * tv1 + tv1.Mul(&tv1, &tv1) // 23. tv1 = tv1 * tv1 Why not write square? + tv5.Mul(&tv4, &tv1) // 24. tv5 = tv4 * tv1 + tv3.Select(int(nE1), &tv3, &tv2) // 25. tv3 = CMOV(tv2, tv3, e1) + tv4.Select(int(nE1), &tv4, &tv5) // 26. tv4 = CMOV(tv5, tv4, e1) + + if i > 2 { + exp.Rsh(&exp, 1) // 18, 19. tv5 = 2ⁱ⁻² + } + } + + *z = tv3 + return isQNr +} + +func g2NotOne(x *fptower.E2) uint64 { + + //Assuming hash is implemented for G1 and that the curve is over Fp + var one fp.Element + return one.SetOne().NotEqual(&x.A0) | g1NotZero(&x.A1) + +} + +// g2MulByZ multiplies x by [12, 1] and stores the result in z +func g2MulByZ(z *fptower.E2, x *fptower.E2) { + + z.Mul(x, &fptower.E2{ + A0: fp.Element{10560307807486212317, 9936456306313395274, 2092561269709285211, 8738829082964617622, 5243865315912343348, 114311569748804731}, + A1: fp.Element{202099033278250856, 5854854902718660529, 11492539364873682930, 8885205928937022213, 5545221690922665192, 39800542322357402}, + }) + +} + +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method +// MapToCurve2 implements the SSWU map +// No cofactor clearing or isogeny +func MapToCurve2(u *fptower.E2) G2Affine { + + var sswuIsoCurveCoeffA = fptower.E2{ + A0: fp.Element{4274545572028848265, 14157081418478689358, 13123833976752631407, 4466041663276938746, 9062541850312583986, 90030181981586611}, + A1: fp.Element{4627353644986202063, 14941155654691983603, 14266958733709189881, 10264689865410103271, 10052798319587953375, 111844286035220969}, + } + var sswuIsoCurveCoeffB = fptower.E2{ + A0: fp.Element{10237434857876739089, 8476639787604822147, 6641637803208190023, 1721529389316620686, 8656544759275761743, 38999476160258021}, + A1: fp.Element{2360755569119276357, 10390833517265838837, 12467133771585386911, 8219721226907645480, 3130947551623757939, 83517800164149569}, + } + + var tv1 fptower.E2 + tv1.Square(u) // 1. tv1 = u² + + //mul tv1 by Z + g2MulByZ(&tv1, &tv1) // 2. tv1 = Z * tv1 + + var tv2 fptower.E2 + tv2.Square(&tv1) // 3. tv2 = tv1² + tv2.Add(&tv2, &tv1) // 4. tv2 = tv2 + tv1 + + var tv3 fptower.E2 + var tv4 fptower.E2 + tv4.SetOne() + tv3.Add(&tv2, &tv4) // 5. tv3 = tv2 + 1 + tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6. tv3 = B * tv3 + + tv2NZero := g2NotZero(&tv2) + + // tv4 = Z + tv4 = fptower.E2{ + A0: fp.Element{10560307807486212317, 9936456306313395274, 2092561269709285211, 8738829082964617622, 5243865315912343348, 114311569748804731}, + A1: fp.Element{202099033278250856, 5854854902718660529, 11492539364873682930, 8885205928937022213, 5545221690922665192, 39800542322357402}, + } + + tv2.Neg(&tv2) + tv4.Select(int(tv2NZero), &tv4, &tv2) // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + tv4.Mul(&tv4, &sswuIsoCurveCoeffA) // 8. tv4 = A * tv4 + + tv2.Square(&tv3) // 9. tv2 = tv3² + + var tv6 fptower.E2 + tv6.Square(&tv4) // 10. tv6 = tv4² + + var tv5 fptower.E2 + tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6 + + tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5 + tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3 + tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4 + + tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6 + tv2.Add(&tv2, &tv5) // 16. tv2 = tv2 + tv5 + + var x fptower.E2 + x.Mul(&tv1, &tv3) // 17. x = tv1 * tv3 + + var y1 fptower.E2 + gx1NSquare := g2SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + + var y fptower.E2 + y.Mul(&tv1, u) // 19. y = tv1 * u + + y.Mul(&y, &y1) // 20. y = y * y1 + + x.Select(int(gx1NSquare), &tv3, &x) // 21. x = CMOV(x, tv3, is_gx1_square) + y.Select(int(gx1NSquare), &y1, &y) // 22. y = CMOV(y, y1, is_gx1_square) + + y1.Neg(&y) + y.Select(int(g2Sgn0(u)^g2Sgn0(&y)), &y, &y1) + + // 23. e1 = sgn0(u) == sgn0(y) + // 24. y = CMOV(-y, y, e1) + + x.Div(&x, &tv4) // 25. x = x / tv4 + + return G2Affine{x, y} +} + +func g2EvalPolynomial(z *fptower.E2, monic bool, coefficients []fptower.E2, x *fptower.E2) { + dst := coefficients[len(coefficients)-1] + + if monic { + dst.Add(&dst, x) + } + + for i := len(coefficients) - 2; i >= 0; i-- { + dst.Mul(&dst, x) + dst.Add(&dst, &coefficients[i]) + } + + z.Set(&dst) +} + +// g2Sgn0 is an algebraic substitute for the notion of sign in ordered fields +// Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function +// The sign of an element is not obviously related to that of its Montgomery form +func g2Sgn0(z *fptower.E2) uint64 { + + nonMont := z.Bits() + + sign := uint64(0) // 1. sign = 0 + zero := uint64(1) // 2. zero = 1 + var signI uint64 + var zeroI uint64 + + // 3. i = 1 + signI = nonMont.A0[0] % 2 // 4. sign_i = x_i mod 2 + zeroI = g1NotZero(&nonMont.A0) + zeroI = 1 ^ (zeroI|-zeroI)>>63 // 5. zero_i = x_i == 0 + sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops + zero = zero & zeroI // 7. zero = zero AND zero_i + // 3. i = 2 + signI = nonMont.A1[0] % 2 // 4. sign_i = x_i mod 2 + // 5. zero_i = x_i == 0 + sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops + // 7. zero = zero AND zero_i + return sign + +} + +// MapToG2 invokes the SSWU map, and guarantees that the result is in g2 +func MapToG2(u fptower.E2) G2Affine { + res := MapToCurve2(&u) + //this is in an isogenous curve + g2Isogeny(&res) + res.ClearCofactor(&res) + return res +} + +// EncodeToG2 hashes a message to a point on the G2 curve using the SSWU map. +// It is faster than HashToG2, but the result is not uniformly distributed. Unsuitable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func EncodeToG2(msg, dst []byte) (G2Affine, error) { + + var res G2Affine + u, err := fp.Hash(msg, dst, 2) + if err != nil { + return res, err + } + + res = MapToCurve2(&fptower.E2{ + A0: u[0], + A1: u[1], + }) + + //this is in an isogenous curve + g2Isogeny(&res) + res.ClearCofactor(&res) + return res, nil +} + +// HashToG2 hashes a message to a point on the G2 curve using the SSWU map. +// Slower than EncodeToG2, but usable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func HashToG2(msg, dst []byte) (G2Affine, error) { + u, err := fp.Hash(msg, dst, 2*2) + if err != nil { + return G2Affine{}, err + } + + Q0 := MapToCurve2(&fptower.E2{ + A0: u[0], + A1: u[1], + }) + Q1 := MapToCurve2(&fptower.E2{ + A0: u[2+0], + A1: u[2+1], + }) + + //TODO (perf): Add in E' first, then apply isogeny + g2Isogeny(&Q0) + g2Isogeny(&Q1) + + var _Q0, _Q1 G2Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1).AddAssign(&_Q0) + + _Q1.ClearCofactor(&_Q1) + + Q1.FromJacobian(&_Q1) + return Q1, nil +} + +func g2NotZero(x *fptower.E2) uint64 { + //Assuming G1 is over Fp and that if hashing is available for G2, it also is for G1 + return g1NotZero(&x.A0) | g1NotZero(&x.A1) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm.go new file mode 100644 index 00000000000..49751a93969 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm.go @@ -0,0 +1,28 @@ +//go:build !noadx +// +build !noadx + +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import "golang.org/x/sys/cpu" + +// supportAdx will be set only on amd64 that has MULX and ADDX instructions +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx // used in asm +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go new file mode 100644 index 00000000000..c6a97081fca --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go @@ -0,0 +1,25 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var supportAdx = false diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go new file mode 100644 index 00000000000..45056247321 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go @@ -0,0 +1,862 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import ( + "errors" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "math/big" + "sync" +) + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +// E12 is a degree two finite field extension of fp6 +type E12 struct { + C0, C1 E6 +} + +// Equal returns true if z equals x, false otherwise +func (z *E12) Equal(x *E12) bool { + return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) +} + +// String puts E12 in string form +func (z *E12) String() string { + return (z.C0.String() + "+(" + z.C1.String() + ")*w") +} + +// SetString sets a E12 from string +func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 { + z.C0.SetString(s0, s1, s2, s3, s4, s5) + z.C1.SetString(s6, s7, s8, s9, s10, s11) + return z +} + +// Set copies x into z and returns z +func (z *E12) Set(x *E12) *E12 { + z.C0 = x.C0 + z.C1 = x.C1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E12) SetOne() *E12 { + *z = E12{} + z.C0.B0.A0.SetOne() + return z +} + +// Add set z=x+y in E12 and return z +func (z *E12) Add(x, y *E12) *E12 { + z.C0.Add(&x.C0, &y.C0) + z.C1.Add(&x.C1, &y.C1) + return z +} + +// Sub sets z to x sub y and return z +func (z *E12) Sub(x, y *E12) *E12 { + z.C0.Sub(&x.C0, &y.C0) + z.C1.Sub(&x.C1, &y.C1) + return z +} + +// Double sets z=2*x and returns z +func (z *E12) Double(x *E12) *E12 { + z.C0.Double(&x.C0) + z.C1.Double(&x.C1) + return z +} + +// SetRandom used only in tests +func (z *E12) SetRandom() (*E12, error) { + if _, err := z.C0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.C1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if the two elements are equal, false otherwise +func (z *E12) IsZero() bool { + return z.C0.IsZero() && z.C1.IsZero() +} + +func (z *E12) IsOne() bool { + return z.C0.IsOne() && z.C1.IsZero() +} + +// Mul set z=x*y in E12 and return z +func (z *E12) Mul(x, y *E12) *E12 { + var a, b, c E6 + a.Add(&x.C0, &x.C1) + b.Add(&y.C0, &y.C1) + a.Mul(&a, &b) + b.Mul(&x.C0, &y.C0) + c.Mul(&x.C1, &y.C1) + z.C1.Sub(&a, &b).Sub(&z.C1, &c) + z.C0.MulByNonResidue(&c).Add(&z.C0, &b) + return z +} + +// Square set z=x*x in E12 and return z +func (z *E12) Square(x *E12) *E12 { + + //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf + var c0, c2, c3 E6 + c0.Sub(&x.C0, &x.C1) + c3.MulByNonResidue(&x.C1).Neg(&c3).Add(&x.C0, &c3) + c2.Mul(&x.C0, &x.C1) + c0.Mul(&c0, &c3).Add(&c0, &c2) + z.C1.Double(&c2) + c2.MulByNonResidue(&c2) + z.C0.Add(&c0, &c2) + + return z +} + +// Karabina's compressed cyclotomic square +// https://eprint.iacr.org/2010/542.pdf +// Th. 3.2 with minor modifications to fit our tower +func (z *E12) CyclotomicSquareCompressed(x *E12) *E12 { + + var t [7]E2 + + // t0 = g1^2 + t[0].Square(&x.C0.B1) + // t1 = g5^2 + t[1].Square(&x.C1.B2) + // t5 = g1 + g5 + t[5].Add(&x.C0.B1, &x.C1.B2) + // t2 = (g1 + g5)^2 + t[2].Square(&t[5]) + + // t3 = g1^2 + g5^2 + t[3].Add(&t[0], &t[1]) + // t5 = 2 * g1 * g5 + t[5].Sub(&t[2], &t[3]) + + // t6 = g3 + g2 + t[6].Add(&x.C1.B0, &x.C0.B2) + // t3 = (g3 + g2)^2 + t[3].Square(&t[6]) + // t2 = g3^2 + t[2].Square(&x.C1.B0) + + // t6 = 2 * nr * g1 * g5 + t[6].MulByNonResidue(&t[5]) + // t5 = 4 * nr * g1 * g5 + 2 * g3 + t[5].Add(&t[6], &x.C1.B0). + Double(&t[5]) + // z3 = 6 * nr * g1 * g5 + 2 * g3 + z.C1.B0.Add(&t[5], &t[6]) + + // t4 = nr * g5^2 + t[4].MulByNonResidue(&t[1]) + // t5 = nr * g5^2 + g1^2 + t[5].Add(&t[0], &t[4]) + // t6 = nr * g5^2 + g1^2 - g2 + t[6].Sub(&t[5], &x.C0.B2) + + // t1 = g2^2 + t[1].Square(&x.C0.B2) + + // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 + t[6].Double(&t[6]) + // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 + z.C0.B2.Add(&t[6], &t[5]) + + // t4 = nr * g2^2 + t[4].MulByNonResidue(&t[1]) + // t5 = g3^2 + nr * g2^2 + t[5].Add(&t[2], &t[4]) + // t6 = g3^2 + nr * g2^2 - g1 + t[6].Sub(&t[5], &x.C0.B1) + // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 + t[6].Double(&t[6]) + // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 + z.C0.B1.Add(&t[6], &t[5]) + + // t0 = g2^2 + g3^2 + t[0].Add(&t[2], &t[1]) + // t5 = 2 * g3 * g2 + t[5].Sub(&t[3], &t[0]) + // t6 = 2 * g3 * g2 + g5 + t[6].Add(&t[5], &x.C1.B2) + // t6 = 4 * g3 * g2 + 2 * g5 + t[6].Double(&t[6]) + // z5 = 6 * g3 * g2 + 2 * g5 + z.C1.B2.Add(&t[5], &t[6]) + + return z +} + +// DecompressKarabina Karabina's cyclotomic square result +// if g3 != 0 +// +// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 +// +// if g3 == 0 +// +// g4 = 2g1g5/g2 +// +// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) +// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} +func (z *E12) DecompressKarabina(x *E12) *E12 { + + var t [3]E2 + var one E2 + one.SetOne() + + if x.C1.B2.IsZero() /* g3 == 0 */ { + t[0].Mul(&x.C0.B1, &x.C1.B2). + Double(&t[0]) + // t1 = g2 + t[1].Set(&x.C0.B2) + + if t[1].IsZero() /* g2 == g3 == 0 */ { + return z.SetOne() + } + } else /* g3 != 0 */ { + + // t0 = g1^2 + t[0].Square(&x.C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t[1].Sub(&t[0], &x.C0.B2). + Double(&t[1]). + Add(&t[1], &t[0]) + // t0 = E * g5^2 + t1 + t[2].Square(&x.C1.B2) + t[0].MulByNonResidue(&t[2]). + Add(&t[0], &t[1]) + // t1 = 4 * g3 + t[1].Double(&x.C1.B0). + Double(&t[1]) + } + + // z4 = g4 + z.C1.B1.Div(&t[0], &t[1]) // costly + + // t1 = g2 * g1 + t[1].Mul(&x.C0.B2, &x.C0.B1) + // t2 = 2 * g4^2 - 3 * g2 * g1 + t[2].Square(&z.C1.B1). + Sub(&t[2], &t[1]). + Double(&t[2]). + Sub(&t[2], &t[1]) + // t1 = g3 * g5 (g3 can be 0) + t[1].Mul(&x.C1.B0, &x.C1.B2) + // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + t[2].Add(&t[2], &t[1]) + z.C0.B0.MulByNonResidue(&t[2]). + Add(&z.C0.B0, &one) + + z.C0.B1.Set(&x.C0.B1) + z.C0.B2.Set(&x.C0.B2) + z.C1.B0.Set(&x.C1.B0) + z.C1.B2.Set(&x.C1.B2) + + return z +} + +// BatchDecompressKarabina multiple Karabina's cyclotomic square results +// if g3 != 0 +// +// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 +// +// if g3 == 0 +// +// g4 = 2g1g5/g2 +// +// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) +// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} +// +// Divisions by 4g3 or g2 is batched using Montgomery batch inverse +func BatchDecompressKarabina(x []E12) []E12 { + + n := len(x) + if n == 0 { + return x + } + + t0 := make([]E2, n) + t1 := make([]E2, n) + t2 := make([]E2, n) + zeroes := make([]bool, n) + + var one E2 + one.SetOne() + + for i := 0; i < n; i++ { + if x[i].C1.B2.IsZero() /* g3 == 0 */ { + t0[i].Mul(&x[i].C0.B1, &x[i].C1.B2). + Double(&t0[i]) + // t1 = g2 + t1[i].Set(&x[i].C0.B2) + + if t1[i].IsZero() /* g3 == g2 == 0 */ { + x[i].SetOne() + zeroes[i] = true + continue + } + } else /* g3 != 0 */ { + // t0 = g1^2 + t0[i].Square(&x[i].C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t1[i].Sub(&t0[i], &x[i].C0.B2). + Double(&t1[i]). + Add(&t1[i], &t0[i]) + // t0 = E * g5^2 + t1 + t2[i].Square(&x[i].C1.B2) + t0[i].MulByNonResidue(&t2[i]). + Add(&t0[i], &t1[i]) + // t1 = 4 * g3 + t1[i].Double(&x[i].C1.B0). + Double(&t1[i]) + } + } + + t1 = BatchInvertE2(t1) // costs 1 inverse + + for i := 0; i < n; i++ { + if zeroes[i] { + continue + } + + // z4 = g4 + x[i].C1.B1.Mul(&t0[i], &t1[i]) + + // t1 = g2 * g1 + t1[i].Mul(&x[i].C0.B2, &x[i].C0.B1) + // t2 = 2 * g4^2 - 3 * g2 * g1 + t2[i].Square(&x[i].C1.B1) + t2[i].Sub(&t2[i], &t1[i]) + t2[i].Double(&t2[i]) + t2[i].Sub(&t2[i], &t1[i]) + + // t1 = g3 * g5 (g3s can be 0s) + t1[i].Mul(&x[i].C1.B0, &x[i].C1.B2) + // z0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + t2[i].Add(&t2[i], &t1[i]) + x[i].C0.B0.MulByNonResidue(&t2[i]). + Add(&x[i].C0.B0, &one) + } + + return x +} + +// Granger-Scott's cyclotomic square +// https://eprint.iacr.org/2009/565.pdf, 3.2 +func (z *E12) CyclotomicSquare(x *E12) *E12 { + + // x=(x0,x1,x2,x3,x4,x5,x6,x7) in E2^6 + // cyclosquare(x)=(3*x4^2*u + 3*x0^2 - 2*x0, + // 3*x2^2*u + 3*x3^2 - 2*x1, + // 3*x5^2*u + 3*x1^2 - 2*x2, + // 6*x1*x5*u + 2*x3, + // 6*x0*x4 + 2*x4, + // 6*x2*x3 + 2*x5) + + var t [9]E2 + + t[0].Square(&x.C1.B1) + t[1].Square(&x.C0.B0) + t[6].Add(&x.C1.B1, &x.C0.B0).Square(&t[6]).Sub(&t[6], &t[0]).Sub(&t[6], &t[1]) // 2*x4*x0 + t[2].Square(&x.C0.B2) + t[3].Square(&x.C1.B0) + t[7].Add(&x.C0.B2, &x.C1.B0).Square(&t[7]).Sub(&t[7], &t[2]).Sub(&t[7], &t[3]) // 2*x2*x3 + t[4].Square(&x.C1.B2) + t[5].Square(&x.C0.B1) + t[8].Add(&x.C1.B2, &x.C0.B1).Square(&t[8]).Sub(&t[8], &t[4]).Sub(&t[8], &t[5]).MulByNonResidue(&t[8]) // 2*x5*x1*u + + t[0].MulByNonResidue(&t[0]).Add(&t[0], &t[1]) // x4^2*u + x0^2 + t[2].MulByNonResidue(&t[2]).Add(&t[2], &t[3]) // x2^2*u + x3^2 + t[4].MulByNonResidue(&t[4]).Add(&t[4], &t[5]) // x5^2*u + x1^2 + + z.C0.B0.Sub(&t[0], &x.C0.B0).Double(&z.C0.B0).Add(&z.C0.B0, &t[0]) + z.C0.B1.Sub(&t[2], &x.C0.B1).Double(&z.C0.B1).Add(&z.C0.B1, &t[2]) + z.C0.B2.Sub(&t[4], &x.C0.B2).Double(&z.C0.B2).Add(&z.C0.B2, &t[4]) + + z.C1.B0.Add(&t[8], &x.C1.B0).Double(&z.C1.B0).Add(&z.C1.B0, &t[8]) + z.C1.B1.Add(&t[6], &x.C1.B1).Double(&z.C1.B1).Add(&z.C1.B1, &t[6]) + z.C1.B2.Add(&t[7], &x.C1.B2).Double(&z.C1.B2).Add(&z.C1.B2, &t[7]) + + return z +} + +// Inverse set z to the inverse of x in E12 and return z +// +// if x == 0, sets and returns z = x +func (z *E12) Inverse(x *E12) *E12 { + // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf + + var t0, t1, tmp E6 + t0.Square(&x.C0) + t1.Square(&x.C1) + tmp.MulByNonResidue(&t1) + t0.Sub(&t0, &tmp) + t1.Inverse(&t0) + z.C0.Mul(&x.C0, &t1) + z.C1.Mul(&x.C1, &t1).Neg(&z.C1) + + return z +} + +// BatchInvertE12 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE12(a []E12) []E12 { + res := make([]E12, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E12 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +// Exp sets z=xᵏ (mod q¹²) and returns it +// uses 2-bits windowed method +func (z *E12) Exp(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var res E12 + var ops [3]E12 + + res.SetOne() + ops[0].Set(&x) + ops[1].Square(&ops[0]) + ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1]) + + b := e.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.Square(&res).Square(&res) + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.Mul(&res, &ops[c-1]) + } + mask = mask >> 2 + } + } + z.Set(&res) + + return z +} + +// CyclotomicExp sets z=xᵏ (mod q¹²) and returns it +// uses 2-NAF decomposition +// x must be in the cyclotomic subgroup +// TODO: use a windowed method +func (z *E12) CyclotomicExp(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert (=conjugate) + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Conjugate(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var res, xInv E12 + xInv.InverseUnitary(&x) + res.SetOne() + eNAF := make([]int8, e.BitLen()+3) + n := ecc.NafDecomposition(e, eNAF[:]) + for i := n - 1; i >= 0; i-- { + res.CyclotomicSquare(&res) + if eNAF[i] == 1 { + res.Mul(&res, &x) + } else if eNAF[i] == -1 { + res.Mul(&res, &xInv) + } + } + z.Set(&res) + return z +} + +// ExpGLV sets z=xᵏ (q¹²) and returns it +// uses 2-dimensional GLV with 2-bits windowed method +// x must be in GT +// TODO: use 2-NAF +// TODO: use higher dimensional decomposition +func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert (=conjugate) + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Conjugate(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var table [15]E12 + var res E12 + var s1, s2 fr.Element + + res.SetOne() + + // table[b3b2b1b0-1] = b3b2*Frobinius(x) + b1b0*x + table[0].Set(&x) + table[3].Frobenius(&x) + + // split the scalar, modifies ±x, Frob(x) accordingly + s := ecc.SplitScalar(e, &glvBasis) + + if s[0].Sign() == -1 { + s[0].Neg(&s[0]) + table[0].InverseUnitary(&table[0]) + } + if s[1].Sign() == -1 { + s[1].Neg(&s[1]) + table[3].InverseUnitary(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2*Frobenius(x) + b1b0*x if b3b2b1b0 != 0 + table[1].CyclotomicSquare(&table[0]) + table[2].Mul(&table[1], &table[0]) + table[4].Mul(&table[3], &table[0]) + table[5].Mul(&table[3], &table[1]) + table[6].Mul(&table[3], &table[2]) + table[7].CyclotomicSquare(&table[3]) + table[8].Mul(&table[7], &table[0]) + table[9].Mul(&table[7], &table[1]) + table[10].Mul(&table[7], &table[2]) + table[11].Mul(&table[7], &table[3]) + table[12].Mul(&table[11], &table[0]) + table[13].Mul(&table[11], &table[1]) + table[14].Mul(&table[11], &table[2]) + + // bounds on the lattice base vectors guarantee that s1, s2 are len(r)/2 bits long max + s1 = s1.SetBigInt(&s[0]).Bits() + s2 = s2.SetBigInt(&s[1]).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(s1)/2 due to the bounds + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.CyclotomicSquare(&res).CyclotomicSquare(&res) + b1 := (s1[i] & mask) >> (62 - 2*j) + b2 := (s2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.Mul(&res, &table[s-1]) + } + mask = mask >> 2 + } + } + + z.Set(&res) + return z +} + +// InverseUnitary inverse a unitary element +func (z *E12) InverseUnitary(x *E12) *E12 { + return z.Conjugate(x) +} + +// Conjugate set z to x conjugated and return z +func (z *E12) Conjugate(x *E12) *E12 { + *z = *x + z.C1.Neg(&z.C1) + return z +} + +// SizeOfGT represents the size in bytes that a GT element need in binary form +const SizeOfGT = 48 * 12 + +// Marshal converts z to a byte slice +func (z *E12) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// Unmarshal is an alias to SetBytes() +func (z *E12) Unmarshal(buf []byte) error { + return z.SetBytes(buf) +} + +// Bytes returns the regular (non montgomery) value +// of z as a big-endian byte array. +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +func (z *E12) Bytes() (r [SizeOfGT]byte) { + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[528:528+fp.Bytes]), z.C0.B0.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[480:480+fp.Bytes]), z.C0.B0.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[432:432+fp.Bytes]), z.C0.B1.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[384:384+fp.Bytes]), z.C0.B1.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[336:336+fp.Bytes]), z.C0.B2.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[288:288+fp.Bytes]), z.C0.B2.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[240:240+fp.Bytes]), z.C1.B0.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[192:192+fp.Bytes]), z.C1.B0.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[144:144+fp.Bytes]), z.C1.B1.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[96:96+fp.Bytes]), z.C1.B1.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[48:48+fp.Bytes]), z.C1.B2.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[0:0+fp.Bytes]), z.C1.B2.A1) + + return +} + +// SetBytes interprets e as the bytes of a big-endian GT +// sets z to that value (in Montgomery form), and returns z. +// size(e) == 48 * 12 +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +func (z *E12) SetBytes(e []byte) error { + if len(e) != SizeOfGT { + return errors.New("invalid buffer size") + } + if err := z.C0.B0.A0.SetBytesCanonical(e[528 : 528+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B0.A1.SetBytesCanonical(e[480 : 480+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B1.A0.SetBytesCanonical(e[432 : 432+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B1.A1.SetBytesCanonical(e[384 : 384+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B2.A0.SetBytesCanonical(e[336 : 336+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B2.A1.SetBytesCanonical(e[288 : 288+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B0.A0.SetBytesCanonical(e[240 : 240+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B0.A1.SetBytesCanonical(e[192 : 192+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B1.A0.SetBytesCanonical(e[144 : 144+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B1.A1.SetBytesCanonical(e[96 : 96+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B2.A0.SetBytesCanonical(e[48 : 48+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B2.A1.SetBytesCanonical(e[0 : 0+fp.Bytes]); err != nil { + return err + } + + return nil +} + +// IsInSubGroup ensures GT/E12 is in correct subgroup +func (z *E12) IsInSubGroup() bool { + var a, b E12 + + // check z^(phi_k(p)) == 1 + a.FrobeniusSquare(z) + b.FrobeniusSquare(&a).Mul(&b, z) + + if !a.Equal(&b) { + return false + } + + // check z^(p+1-t) == 1 + a.Frobenius(z) + b.Expt(z) + + return a.Equal(&b) +} + +// CompressTorus GT/E12 element to half its size +// z must be in the cyclotomic subgroup +// i.e. z^(p^4-p^2+1)=1 +// e.g. GT +// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG +// z.C1 == 0 only when z \in {-1,1} +func (z *E12) CompressTorus() (E6, error) { + + if z.C1.IsZero() { + return E6{}, errors.New("invalid input") + } + + var res, tmp, one E6 + one.SetOne() + tmp.Inverse(&z.C1) + res.Add(&z.C0, &one). + Mul(&res, &tmp) + + return res, nil +} + +// BatchCompressTorus GT/E12 elements to half their size using a batch inversion. +// +// if len(x) == 0 or if any of the x[i].C1 coordinate is 0, this function returns an error. +func BatchCompressTorus(x []E12) ([]E6, error) { + + n := len(x) + if n == 0 { + return nil, errors.New("invalid input size") + } + + var one E6 + one.SetOne() + res := make([]E6, n) + + for i := 0; i < n; i++ { + res[i].Set(&x[i].C1) + // throw an error if any of the x[i].C1 is 0 + if res[i].IsZero() { + return nil, errors.New("invalid input; C1 is 0") + } + } + + t := BatchInvertE6(res) // costs 1 inverse + + for i := 0; i < n; i++ { + res[i].Add(&x[i].C0, &one). + Mul(&res[i], &t[i]) + } + + return res, nil +} + +// DecompressTorus GT/E12 a compressed element +// element must be in the cyclotomic subgroup +// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG +func (z *E6) DecompressTorus() E12 { + + var res, num, denum E12 + num.C0.Set(z) + num.C1.SetOne() + denum.C0.Set(z) + denum.C1.SetOne().Neg(&denum.C1) + res.Inverse(&denum). + Mul(&res, &num) + + return res +} + +// BatchDecompressTorus GT/E12 compressed elements +// using a batch inversion +func BatchDecompressTorus(x []E6) ([]E12, error) { + + n := len(x) + if n == 0 { + return []E12{}, errors.New("invalid input size") + } + + res := make([]E12, n) + num := make([]E12, n) + denum := make([]E12, n) + + for i := 0; i < n; i++ { + num[i].C0.Set(&x[i]) + num[i].C1.SetOne() + denum[i].C0.Set(&x[i]) + denum[i].C1.SetOne().Neg(&denum[i].C1) + } + + denum = BatchInvertE12(denum) // costs 1 inverse + + for i := 0; i < n; i++ { + res[i].Mul(&num[i], &denum[i]) + } + + return res, nil +} + +func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.C0.Select(cond, &caseZ.C0, &caseNz.C0) + z.C1.Select(cond, &caseZ.C1, &caseNz.C1) + + return z +} + +func (z *E12) Div(x *E12, y *E12) *E12 { + var r E12 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12_pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12_pairing.go new file mode 100644 index 00000000000..6888dfc4fca --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12_pairing.go @@ -0,0 +1,113 @@ +package fptower + +func (z *E12) nSquare(n int) { + for i := 0; i < n; i++ { + z.CyclotomicSquare(z) + } +} + +func (z *E12) nSquareCompressed(n int) { + for i := 0; i < n; i++ { + z.CyclotomicSquareCompressed(z) + } +} + +// Expt set z to x^t in E12 and return z +func (z *E12) Expt(x *E12) *E12 { + // const tAbsVal uint64 = 9586122913090633729 + // tAbsVal in binary: 1000010100001000110000000000000000000000000000000000000000000001 + // drop the low 46 bits (all 0 except the least significant bit): 100001010000100011 = 136227 + // Shortest addition chains can be found at https://wwwhomes.uni-bielefeld.de/achim/addition_chain.html + + var result, x33 E12 + + // a shortest addition chain for 136227 + result.Set(x) + result.nSquare(5) + result.Mul(&result, x) + x33.Set(&result) + result.nSquare(7) + result.Mul(&result, &x33) + result.nSquare(4) + result.Mul(&result, x) + result.CyclotomicSquare(&result) + result.Mul(&result, x) + + // the remaining 46 bits + result.nSquareCompressed(46) + result.DecompressKarabina(&result) + result.Mul(&result, x) + + z.Set(&result) + return z +} + +// MulBy034 multiplication by sparse element (c0,0,0,c3,c4,0) +func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 { + + var a, b, d E6 + + a.MulByE2(&z.C0, c0) + + b.Set(&z.C1) + b.MulBy01(c3, c4) + + c0.Add(c0, c3) + d.Add(&z.C0, &z.C1) + d.MulBy01(c0, c4) + + z.C1.Add(&a, &b).Neg(&z.C1).Add(&z.C1, &d) + z.C0.MulByNonResidue(&b).Add(&z.C0, &a) + + return z +} + +// Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0) +func Mul034By034(d0, d3, d4, c0, c3, c4 *E2) [5]E2 { + var z00, tmp, x0, x3, x4, x04, x03, x34 E2 + x0.Mul(c0, d0) + x3.Mul(c3, d3) + x4.Mul(c4, d4) + tmp.Add(c0, c4) + x04.Add(d0, d4). + Mul(&x04, &tmp). + Sub(&x04, &x0). + Sub(&x04, &x4) + tmp.Add(c0, c3) + x03.Add(d0, d3). + Mul(&x03, &tmp). + Sub(&x03, &x0). + Sub(&x03, &x3) + tmp.Add(c3, c4) + x34.Add(d3, d4). + Mul(&x34, &tmp). + Sub(&x34, &x3). + Sub(&x34, &x4) + + z00.MulByNonResidue(&x4). + Add(&z00, &x0) + + return [5]E2{z00, x3, x34, x03, x04} +} + +// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0) +func (z *E12) MulBy01234(x *[5]E2) *E12 { + var c1, a, b, c, z0, z1 E6 + c0 := &E6{B0: x[0], B1: x[1], B2: x[2]} + c1.B0 = x[3] + c1.B1 = x[4] + a.Add(&z.C0, &z.C1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.C0, c0) + c.Set(&z.C1).MulBy01(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.C0 = z0 + z.C1 = z1 + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2.go new file mode 100644 index 00000000000..874802d7433 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2.go @@ -0,0 +1,294 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "math/big" +) + +// E2 is a degree two finite field extension of fp.Element +type E2 struct { + A0, A1 fp.Element +} + +// Equal returns true if z equals x, false otherwise +func (z *E2) Equal(x *E2) bool { + return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) +} + +// Bits +// TODO @gbotrel fixme this shouldn't return a E2 +func (z *E2) Bits() E2 { + r := E2{} + r.A0 = z.A0.Bits() + r.A1 = z.A1.Bits() + return r +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *E2) Cmp(x *E2) int { + if a1 := z.A1.Cmp(&x.A1); a1 != 0 { + return a1 + } + return z.A0.Cmp(&x.A0) +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *E2) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + if z.A1.IsZero() { + return z.A0.LexicographicallyLargest() + } + return z.A1.LexicographicallyLargest() +} + +// SetString sets a E2 element from strings +func (z *E2) SetString(s1, s2 string) *E2 { + z.A0.SetString(s1) + z.A1.SetString(s2) + return z +} + +// SetZero sets an E2 elmt to zero +func (z *E2) SetZero() *E2 { + z.A0.SetZero() + z.A1.SetZero() + return z +} + +// Set sets an E2 from x +func (z *E2) Set(x *E2) *E2 { + z.A0 = x.A0 + z.A1 = x.A1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E2) SetOne() *E2 { + z.A0.SetOne() + z.A1.SetZero() + return z +} + +// SetRandom sets a0 and a1 to random values +func (z *E2) SetRandom() (*E2, error) { + if _, err := z.A0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.A1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if the two elements are equal, false otherwise +func (z *E2) IsZero() bool { + return z.A0.IsZero() && z.A1.IsZero() +} + +func (z *E2) IsOne() bool { + return z.A0.IsOne() && z.A1.IsZero() +} + +// Add adds two elements of E2 +func (z *E2) Add(x, y *E2) *E2 { + addE2(z, x, y) + return z +} + +// Sub two elements of E2 +func (z *E2) Sub(x, y *E2) *E2 { + subE2(z, x, y) + return z +} + +// Double doubles an E2 element +func (z *E2) Double(x *E2) *E2 { + doubleE2(z, x) + return z +} + +// Neg negates an E2 element +func (z *E2) Neg(x *E2) *E2 { + negE2(z, x) + return z +} + +// String implements Stringer interface for fancy printing +func (z *E2) String() string { + return z.A0.String() + "+" + z.A1.String() + "*u" +} + +// MulByElement multiplies an element in E2 by an element in fp +func (z *E2) MulByElement(x *E2, y *fp.Element) *E2 { + var yCopy fp.Element + yCopy.Set(y) + z.A0.Mul(&x.A0, &yCopy) + z.A1.Mul(&x.A1, &yCopy) + return z +} + +// Conjugate conjugates an element in E2 +func (z *E2) Conjugate(x *E2) *E2 { + z.A0 = x.A0 + z.A1.Neg(&x.A1) + return z +} + +// Halve sets z = z / 2 +func (z *E2) Halve() { + z.A0.Halve() + z.A1.Halve() +} + +// Legendre returns the Legendre symbol of z +func (z *E2) Legendre() int { + var n fp.Element + z.norm(&n) + return n.Legendre() +} + +// Exp sets z=xᵏ (mod q²) and returns it +func (z *E2) Exp(x E2, k *big.Int) *E2 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q²) == (x⁻¹)ᵏ (mod q²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + z.SetOne() + b := e.Bytes() + for i := 0; i < len(b); i++ { + w := b[i] + for j := 0; j < 8; j++ { + z.Square(z) + if (w & (0b10000000 >> j)) != 0 { + z.Mul(z, &x) + } + } + } + + return z +} + +// Sqrt sets z to the square root of and returns z +// The function does not test whether the square root +// exists or not, it's up to the caller to call +// Legendre beforehand. +// cf https://eprint.iacr.org/2012/685.pdf (algo 10) +func (z *E2) Sqrt(x *E2) *E2 { + + // precomputation + var b, c, d, e, f, x0 E2 + var _b, o fp.Element + + // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) + c.A1.SetOne() + + q := fp.Modulus() + var exp, one big.Int + one.SetUint64(1) + exp.Set(q).Sub(&exp, &one).Rsh(&exp, 1) + d.Exp(c, &exp) + e.Mul(&d, &c).Inverse(&e) + f.Mul(&d, &c).Square(&f) + + // computation + exp.Rsh(&exp, 1) + b.Exp(*x, &exp) + b.norm(&_b) + o.SetOne() + if _b.Equal(&o) { + x0.Square(&b).Mul(&x0, x) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b) + return z + } + x0.Square(&b).Mul(&x0, x).Mul(&x0, &f) + _b.Set(&x0.A0).Sqrt(&_b) + z.Conjugate(&b).MulByElement(z, &_b).Mul(z, &e) + + return z +} + +// BatchInvertE2 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE2(a []E2) []E2 { + res := make([]E2, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E2 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.A0.Select(cond, &caseZ.A0, &caseNz.A0) + z.A1.Select(cond, &caseZ.A1, &caseNz.A1) + + return z +} + +func (z *E2) Div(x *E2, y *E2) *E2 { + var r E2 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.go new file mode 100644 index 00000000000..ac68ffa5782 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.go @@ -0,0 +1,29 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +//go:noescape +func addE2(res, x, y *E2) + +//go:noescape +func subE2(res, x, y *E2) + +//go:noescape +func doubleE2(res, x *E2) + +//go:noescape +func negE2(res, x *E2) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.s new file mode 100644 index 00000000000..053bd8ded17 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_amd64.s @@ -0,0 +1,320 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0x8508c00000000001 +DATA q<>+8(SB)/8, $0x170b5d4430000000 +DATA q<>+16(SB)/8, $0x1ef3622fba094800 +DATA q<>+24(SB)/8, $0x1a22d9f300f5138f +DATA q<>+32(SB)/8, $0xc63b05c06ca1493b +DATA q<>+40(SB)/8, $0x01ae3a4617c510ea +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x8508bfffffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +TEXT ·addE2(SB), NOSPLIT, $0-24 + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ 32(AX), R9 + MOVQ 40(AX), R10 + MOVQ y+16(FP), DX + ADDQ 0(DX), BX + ADCQ 8(DX), SI + ADCQ 16(DX), DI + ADCQ 24(DX), R8 + ADCQ 32(DX), R9 + ADCQ 40(DX), R10 + + // reduce element(BX,SI,DI,R8,R9,R10) using temp registers (R11,R12,R13,R14,R15,s0-8(SP)) + REDUCE(BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15,s0-8(SP)) + + MOVQ res+0(FP), CX + MOVQ BX, 0(CX) + MOVQ SI, 8(CX) + MOVQ DI, 16(CX) + MOVQ R8, 24(CX) + MOVQ R9, 32(CX) + MOVQ R10, 40(CX) + MOVQ 48(AX), BX + MOVQ 56(AX), SI + MOVQ 64(AX), DI + MOVQ 72(AX), R8 + MOVQ 80(AX), R9 + MOVQ 88(AX), R10 + ADDQ 48(DX), BX + ADCQ 56(DX), SI + ADCQ 64(DX), DI + ADCQ 72(DX), R8 + ADCQ 80(DX), R9 + ADCQ 88(DX), R10 + + // reduce element(BX,SI,DI,R8,R9,R10) using temp registers (R11,R12,R13,R14,R15,s0-8(SP)) + REDUCE(BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15,s0-8(SP)) + + MOVQ BX, 48(CX) + MOVQ SI, 56(CX) + MOVQ DI, 64(CX) + MOVQ R8, 72(CX) + MOVQ R9, 80(CX) + MOVQ R10, 88(CX) + RET + +TEXT ·doubleE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ 32(AX), R8 + MOVQ 40(AX), R9 + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + ADCQ R9, R9 + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ CX, 0(DX) + MOVQ BX, 8(DX) + MOVQ SI, 16(DX) + MOVQ DI, 24(DX) + MOVQ R8, 32(DX) + MOVQ R9, 40(DX) + MOVQ 48(AX), CX + MOVQ 56(AX), BX + MOVQ 64(AX), SI + MOVQ 72(AX), DI + MOVQ 80(AX), R8 + MOVQ 88(AX), R9 + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + ADCQ R9, R9 + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ CX, 48(DX) + MOVQ BX, 56(DX) + MOVQ SI, 64(DX) + MOVQ DI, 72(DX) + MOVQ R8, 80(DX) + MOVQ R9, 88(DX) + RET + +TEXT ·subE2(SB), NOSPLIT, $0-24 + XORQ R9, R9 + MOVQ x+8(FP), R8 + MOVQ 0(R8), AX + MOVQ 8(R8), DX + MOVQ 16(R8), CX + MOVQ 24(R8), BX + MOVQ 32(R8), SI + MOVQ 40(R8), DI + MOVQ y+16(FP), R8 + SUBQ 0(R8), AX + SBBQ 8(R8), DX + SBBQ 16(R8), CX + SBBQ 24(R8), BX + SBBQ 32(R8), SI + SBBQ 40(R8), DI + MOVQ x+8(FP), R8 + MOVQ $0x8508c00000000001, R10 + MOVQ $0x170b5d4430000000, R11 + MOVQ $0x1ef3622fba094800, R12 + MOVQ $0x1a22d9f300f5138f, R13 + MOVQ $0xc63b05c06ca1493b, R14 + MOVQ $0x01ae3a4617c510ea, R15 + CMOVQCC R9, R10 + CMOVQCC R9, R11 + CMOVQCC R9, R12 + CMOVQCC R9, R13 + CMOVQCC R9, R14 + CMOVQCC R9, R15 + ADDQ R10, AX + ADCQ R11, DX + ADCQ R12, CX + ADCQ R13, BX + ADCQ R14, SI + ADCQ R15, DI + MOVQ res+0(FP), R10 + MOVQ AX, 0(R10) + MOVQ DX, 8(R10) + MOVQ CX, 16(R10) + MOVQ BX, 24(R10) + MOVQ SI, 32(R10) + MOVQ DI, 40(R10) + MOVQ 48(R8), AX + MOVQ 56(R8), DX + MOVQ 64(R8), CX + MOVQ 72(R8), BX + MOVQ 80(R8), SI + MOVQ 88(R8), DI + MOVQ y+16(FP), R8 + SUBQ 48(R8), AX + SBBQ 56(R8), DX + SBBQ 64(R8), CX + SBBQ 72(R8), BX + SBBQ 80(R8), SI + SBBQ 88(R8), DI + MOVQ $0x8508c00000000001, R11 + MOVQ $0x170b5d4430000000, R12 + MOVQ $0x1ef3622fba094800, R13 + MOVQ $0x1a22d9f300f5138f, R14 + MOVQ $0xc63b05c06ca1493b, R15 + MOVQ $0x01ae3a4617c510ea, R10 + CMOVQCC R9, R11 + CMOVQCC R9, R12 + CMOVQCC R9, R13 + CMOVQCC R9, R14 + CMOVQCC R9, R15 + CMOVQCC R9, R10 + ADDQ R11, AX + ADCQ R12, DX + ADCQ R13, CX + ADCQ R14, BX + ADCQ R15, SI + ADCQ R10, DI + MOVQ res+0(FP), R8 + MOVQ AX, 48(R8) + MOVQ DX, 56(R8) + MOVQ CX, 64(R8) + MOVQ BX, 72(R8) + MOVQ SI, 80(R8) + MOVQ DI, 88(R8) + RET + +TEXT ·negE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ 32(AX), R9 + MOVQ 40(AX), R10 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + ORQ R9, AX + ORQ R10, AX + TESTQ AX, AX + JNE l1 + MOVQ AX, 0(DX) + MOVQ AX, 8(DX) + MOVQ AX, 16(DX) + MOVQ AX, 24(DX) + MOVQ AX, 32(DX) + MOVQ AX, 40(DX) + JMP l3 + +l1: + MOVQ $0x8508c00000000001, CX + SUBQ BX, CX + MOVQ CX, 0(DX) + MOVQ $0x170b5d4430000000, CX + SBBQ SI, CX + MOVQ CX, 8(DX) + MOVQ $0x1ef3622fba094800, CX + SBBQ DI, CX + MOVQ CX, 16(DX) + MOVQ $0x1a22d9f300f5138f, CX + SBBQ R8, CX + MOVQ CX, 24(DX) + MOVQ $0xc63b05c06ca1493b, CX + SBBQ R9, CX + MOVQ CX, 32(DX) + MOVQ $0x01ae3a4617c510ea, CX + SBBQ R10, CX + MOVQ CX, 40(DX) + +l3: + MOVQ x+8(FP), AX + MOVQ 48(AX), BX + MOVQ 56(AX), SI + MOVQ 64(AX), DI + MOVQ 72(AX), R8 + MOVQ 80(AX), R9 + MOVQ 88(AX), R10 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + ORQ R9, AX + ORQ R10, AX + TESTQ AX, AX + JNE l2 + MOVQ AX, 48(DX) + MOVQ AX, 56(DX) + MOVQ AX, 64(DX) + MOVQ AX, 72(DX) + MOVQ AX, 80(DX) + MOVQ AX, 88(DX) + RET + +l2: + MOVQ $0x8508c00000000001, CX + SUBQ BX, CX + MOVQ CX, 48(DX) + MOVQ $0x170b5d4430000000, CX + SBBQ SI, CX + MOVQ CX, 56(DX) + MOVQ $0x1ef3622fba094800, CX + SBBQ DI, CX + MOVQ CX, 64(DX) + MOVQ $0x1a22d9f300f5138f, CX + SBBQ R8, CX + MOVQ CX, 72(DX) + MOVQ $0xc63b05c06ca1493b, CX + SBBQ R9, CX + MOVQ CX, 80(DX) + MOVQ $0x01ae3a4617c510ea, CX + SBBQ R10, CX + MOVQ CX, 88(DX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_bls377.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_bls377.go new file mode 100644 index 00000000000..9505d531533 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_bls377.go @@ -0,0 +1,117 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" +) + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { + var a, b, c fp.Element + a.Add(&x.A0, &x.A1) + b.Add(&y.A0, &y.A1) + a.Mul(&a, &b) + b.Mul(&x.A0, &y.A0) + c.Mul(&x.A1, &y.A1) + z.A1.Sub(&a, &b).Sub(&z.A1, &c) + fp.MulBy5(&c) + z.A0.Sub(&b, &c) + return z +} + +// Square sets z to the E2-product of x,x returns z +func (z *E2) Square(x *E2) *E2 { + //algo 22 https://eprint.iacr.org/2010/354.pdf + var c0, c2 fp.Element + c0.Add(&x.A0, &x.A1) + c2.Neg(&x.A1) + fp.MulBy5(&c2) + c2.Add(&c2, &x.A0) + + c0.Mul(&c0, &c2) // (x1+x2)*(x1+(u**2)x2) + c2.Mul(&x.A0, &x.A1).Double(&c2) + z.A1 = c2 + c2.Double(&c2) + z.A0.Add(&c0, &c2) + + return z +} + +// MulByNonResidue multiplies a E2 by (0,1) +func (z *E2) MulByNonResidue(x *E2) *E2 { + a := x.A0 + b := x.A1 // fetching x.A1 in the function below is slower + fp.MulBy5(&b) + z.A0.Neg(&b) + z.A1 = a + return z +} + +// MulByNonResidueInv multiplies a E2 by (0,1)^{-1} +func (z *E2) MulByNonResidueInv(x *E2) *E2 { + //z.A1.MulByNonResidueInv(&x.A0) + a := x.A1 + fiveinv := fp.Element{ + 330620507644336508, + 9878087358076053079, + 11461392860540703536, + 6973035786057818995, + 8846909097162646007, + 104838758629667239, + } + z.A1.Mul(&x.A0, &fiveinv).Neg(&z.A1) + z.A0 = a + return z +} + +// Inverse sets z to the E2-inverse of x, returns z +func (z *E2) Inverse(x *E2) *E2 { + // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf + //var a, b, t0, t1, tmp fp.Element + var t0, t1, tmp fp.Element + a := &x.A0 // creating the buffers a, b is faster than querying &x.A0, &x.A1 in the functions call below + b := &x.A1 + t0.Square(a) + t1.Square(b) + tmp.Set(&t1) + fp.MulBy5(&tmp) + t0.Add(&t0, &tmp) + t1.Inverse(&t0) + z.A0.Mul(a, &t1) + z.A1.Mul(b, &t1).Neg(&z.A1) + + return z +} + +// norm sets x to the norm of z +func (z *E2) norm(x *fp.Element) { + var tmp fp.Element + x.Square(&z.A1) + tmp.Set(x) + fp.MulBy5(&tmp) + x.Square(&z.A0).Add(x, &tmp) +} + +// MulBybTwistCurveCoeff multiplies by 1/(0,1) +func (z *E2) MulBybTwistCurveCoeff(x *E2) *E2 { + + var res E2 + res.A0.Set(&x.A1) + res.A1.MulByNonResidueInv(&x.A0) + z.Set(&res) + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_fallback.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_fallback.go new file mode 100644 index 00000000000..6fe47c4111b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e2_fallback.go @@ -0,0 +1,40 @@ +//go:build !amd64 +// +build !amd64 + +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +func addE2(z, x, y *E2) { + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) +} + +func subE2(z, x, y *E2) { + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) +} + +func doubleE2(z, x *E2) { + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) +} + +func negE2(z, x *E2) { + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go new file mode 100644 index 00000000000..128007df278 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go @@ -0,0 +1,339 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +// E6 is a degree three finite field extension of fp2 +type E6 struct { + B0, B1, B2 E2 +} + +// Equal returns true if z equals x, false otherwise +func (z *E6) Equal(x *E6) bool { + return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) && z.B2.Equal(&x.B2) +} + +// SetString sets a E6 elmt from stringf +func (z *E6) SetString(s1, s2, s3, s4, s5, s6 string) *E6 { + z.B0.SetString(s1, s2) + z.B1.SetString(s3, s4) + z.B2.SetString(s5, s6) + return z +} + +// Set Sets a E6 elmt form another E6 elmt +func (z *E6) Set(x *E6) *E6 { + z.B0 = x.B0 + z.B1 = x.B1 + z.B2 = x.B2 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E6) SetOne() *E6 { + *z = E6{} + z.B0.A0.SetOne() + return z +} + +// SetRandom set z to a random elmt +func (z *E6) SetRandom() (*E6, error) { + if _, err := z.B0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B1.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B2.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if the two elements are equal, false otherwise +func (z *E6) IsZero() bool { + return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() +} + +func (z *E6) IsOne() bool { + return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() +} + +// Add adds two elements of E6 +func (z *E6) Add(x, y *E6) *E6 { + z.B0.Add(&x.B0, &y.B0) + z.B1.Add(&x.B1, &y.B1) + z.B2.Add(&x.B2, &y.B2) + return z +} + +// Neg negates the E6 number +func (z *E6) Neg(x *E6) *E6 { + z.B0.Neg(&x.B0) + z.B1.Neg(&x.B1) + z.B2.Neg(&x.B2) + return z +} + +// Sub two elements of E6 +func (z *E6) Sub(x, y *E6) *E6 { + z.B0.Sub(&x.B0, &y.B0) + z.B1.Sub(&x.B1, &y.B1) + z.B2.Sub(&x.B2, &y.B2) + return z +} + +// Double doubles an element in E6 +func (z *E6) Double(x *E6) *E6 { + z.B0.Double(&x.B0) + z.B1.Double(&x.B1) + z.B2.Double(&x.B2) + return z +} + +// String puts E6 elmt in string form +func (z *E6) String() string { + return (z.B0.String() + "+(" + z.B1.String() + ")*v+(" + z.B2.String() + ")*v**2") +} + +// MulByNonResidue mul x by (0,1,0) +func (z *E6) MulByNonResidue(x *E6) *E6 { + z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z.B0.MulByNonResidue(&z.B0) + return z +} + +// MulByE2 multiplies an element in E6 by an element in E2 +func (z *E6) MulByE2(x *E6, y *E2) *E6 { + var yCopy E2 + yCopy.Set(y) + z.B0.Mul(&x.B0, &yCopy) + z.B1.Mul(&x.B1, &yCopy) + z.B2.Mul(&x.B2, &yCopy) + return z +} + +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + +// MulBy01 multiplication by sparse element (c0,c1,0) +func (z *E6) MulBy01(c0, c1 *E2) *E6 { + + var a, b, tmp, t0, t1, t2 E2 + + a.Mul(&z.B0, c0) + b.Mul(&z.B1, c1) + + tmp.Add(&z.B1, &z.B2) + t0.Mul(c1, &tmp) + t0.Sub(&t0, &b) + t0.MulByNonResidue(&t0) + t0.Add(&t0, &a) + + tmp.Add(&z.B0, &z.B2) + t2.Mul(c0, &tmp) + t2.Sub(&t2, &a) + t2.Add(&t2, &b) + + t1.Add(c0, c1) + tmp.Add(&z.B0, &z.B1) + t1.Mul(&t1, &tmp) + t1.Sub(&t1, &a) + t1.Sub(&t1, &b) + + z.B0.Set(&t0) + z.B1.Set(&t1) + z.B2.Set(&t2) + + return z +} + +// MulBy1 multiplication of E6 by sparse element (0, c1, 0) +func (z *E6) MulBy1(c1 *E2) *E6 { + + var b, tmp, t0, t1 E2 + b.Mul(&z.B1, c1) + + tmp.Add(&z.B1, &z.B2) + t0.Mul(c1, &tmp) + t0.Sub(&t0, &b) + t0.MulByNonResidue(&t0) + + tmp.Add(&z.B0, &z.B1) + t1.Mul(c1, &tmp) + t1.Sub(&t1, &b) + + z.B0.Set(&t0) + z.B1.Set(&t1) + z.B2.Set(&b) + + return z +} + +// Mul sets z to the E6 product of x,y, returns z +func (z *E6) Mul(x, y *E6) *E6 { + // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + var t0, t1, t2, c0, c1, c2, tmp E2 + t0.Mul(&x.B0, &y.B0) + t1.Mul(&x.B1, &y.B1) + t2.Mul(&x.B2, &y.B2) + + c0.Add(&x.B1, &x.B2) + tmp.Add(&y.B1, &y.B2) + c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0) + + c1.Add(&x.B0, &x.B1) + tmp.Add(&y.B0, &y.B1) + c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + + tmp.Add(&x.B0, &x.B2) + c2.Add(&y.B0, &y.B2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1) + + z.B0.Set(&c0) + z.B1.Set(&c1) + z.B2.Set(&c2) + + return z +} + +// Square sets z to the E6 product of x,x, returns z +func (z *E6) Square(x *E6) *E6 { + + // Algorithm 16 from https://eprint.iacr.org/2010/354.pdf + var c4, c5, c1, c2, c3, c0 E2 + c4.Mul(&x.B0, &x.B1).Double(&c4) + c5.Square(&x.B2) + c1.MulByNonResidue(&c5).Add(&c1, &c4) + c2.Sub(&c4, &c5) + c3.Square(&x.B0) + c4.Sub(&x.B0, &x.B1).Add(&c4, &x.B2) + c5.Mul(&x.B1, &x.B2).Double(&c5) + c4.Square(&c4) + c0.MulByNonResidue(&c5).Add(&c0, &c3) + z.B2.Add(&c2, &c4).Add(&z.B2, &c5).Sub(&z.B2, &c3) + z.B0.Set(&c0) + z.B1.Set(&c1) + + return z +} + +// Inverse an element in E6 +// +// if x == 0, sets and returns z = x +func (z *E6) Inverse(x *E6) *E6 { + // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf + // step 9 is wrong in the paper it's t1-t4 + var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0.Square(&x.B0) + t1.Square(&x.B1) + t2.Square(&x.B2) + t3.Mul(&x.B0, &x.B1) + t4.Mul(&x.B0, &x.B2) + t5.Mul(&x.B1, &x.B2) + c0.MulByNonResidue(&t5).Neg(&c0).Add(&c0, &t0) + c1.MulByNonResidue(&t2).Sub(&c1, &t3) + c2.Sub(&t1, &t4) + t6.Mul(&x.B0, &c0) + d1.Mul(&x.B2, &c1) + d2.Mul(&x.B1, &c2) + d1.Add(&d1, &d2).MulByNonResidue(&d1) + t6.Add(&t6, &d1) + t6.Inverse(&t6) + z.B0.Mul(&c0, &t6) + z.B1.Mul(&c1, &t6) + z.B2.Mul(&c2, &t6) + + return z +} + +// BatchInvertE6 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE6(a []E6) []E6 { + res := make([]E6, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E6 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.B0.Select(cond, &caseZ.B0, &caseNz.B0) + z.B1.Select(cond, &caseZ.B1, &caseNz.B1) + z.B2.Select(cond, &caseZ.B2, &caseNz.B2) + + return z +} + +func (z *E6) Div(x *E6, y *E6) *E6 { + var r E6 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/frobenius.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/frobenius.go new file mode 100644 index 00000000000..a7e1b2a812a --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/frobenius.go @@ -0,0 +1,227 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + +// Frobenius set z to Frobenius(x), return z +func (z *E12) Frobenius(x *E12) *E12 { + // Algorithm 28 from https://eprint.iacr.org/2010/354.pdf (beware typos!) + var t [6]E2 + + // Frobenius acts on fp2 by conjugation + t[0].Conjugate(&x.C0.B0) + t[1].Conjugate(&x.C0.B1) + t[2].Conjugate(&x.C0.B2) + t[3].Conjugate(&x.C1.B0) + t[4].Conjugate(&x.C1.B1) + t[5].Conjugate(&x.C1.B2) + + t[1].MulByNonResidue1Power2(&t[1]) + t[2].MulByNonResidue1Power4(&t[2]) + t[3].MulByNonResidue1Power1(&t[3]) + t[4].MulByNonResidue1Power3(&t[4]) + t[5].MulByNonResidue1Power5(&t[5]) + + z.C0.B0 = t[0] + z.C0.B1 = t[1] + z.C0.B2 = t[2] + z.C1.B0 = t[3] + z.C1.B1 = t[4] + z.C1.B2 = t[5] + + return z +} + +// FrobeniusSquare set z to Frobenius^2(x), and return z +func (z *E12) FrobeniusSquare(x *E12) *E12 { + // Algorithm 29 from https://eprint.iacr.org/2010/354.pdf (beware typos!) + var t [6]E2 + + t[1].MulByNonResidue2Power2(&x.C0.B1) + t[2].MulByNonResidue2Power4(&x.C0.B2) + t[3].MulByNonResidue2Power1(&x.C1.B0) + t[4].MulByNonResidue2Power3(&x.C1.B1) + t[5].MulByNonResidue2Power5(&x.C1.B2) + + z.C0.B0 = x.C0.B0 + z.C0.B1 = t[1] + z.C0.B2 = t[2] + z.C1.B0 = t[3] + z.C1.B1 = t[4] + z.C1.B2 = t[5] + + return z +} + +// MulByNonResidue1Power1 set z=x*(0,1)^(1*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power1(x *E2) *E2 { + // 92949345220277864758624960506473182677953048909283248980960104381795901929519566951595905490535835115111760994353 + b := fp.Element{ + 7981638599956744862, + 11830407261614897732, + 6308788297503259939, + 10596665404780565693, + 11693741422477421038, + 61545186993886319, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power2 set z=x*(0,1)^(2*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power2(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946 + b := fp.Element{ + 6382252053795993818, + 1383562296554596171, + 11197251941974877903, + 6684509567199238270, + 6699184357838251020, + 19987743694136192, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power3 set z=x*(0,1)^(3*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power3(x *E2) *E2 { + // 216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499 + b := fp.Element{ + 10965161018967488287, + 18251363109856037426, + 7036083669251591763, + 16109345360066746489, + 4679973768683352764, + 96952949334633821, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power4 set z=x*(0,1)^(4*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power4(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945 + b := fp.Element{ + 15766275933608376691, + 15635974902606112666, + 1934946774703877852, + 18129354943882397960, + 15437979634065614942, + 101285514078273488, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power5 set z=x*(0,1)^(5*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power5(x *E2) *E2 { + // 123516416119946754630746545296132064952198520638002533875843642777304321125866014634106496325844844051843001220146 + b := fp.Element{ + 2983522419010743425, + 6420955848241139694, + 727295371748331824, + 5512679955286180796, + 11432976419915483342, + 35407762340747501, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power1 set z=x*(0,1)^(1*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power1(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946 + b := fp.Element{ + 6382252053795993818, + 1383562296554596171, + 11197251941974877903, + 6684509567199238270, + 6699184357838251020, + 19987743694136192, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power2 set z=x*(0,1)^(2*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power2(x *E2) *E2 { + // 80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945 + b := fp.Element{ + 15766275933608376691, + 15635974902606112666, + 1934946774703877852, + 18129354943882397960, + 15437979634065614942, + 101285514078273488, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power3 set z=x*(0,1)^(3*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power3(x *E2) *E2 { + // 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458176 + b := fp.Element{ + 9384023879812382873, + 14252412606051516495, + 9184438906438551565, + 11444845376683159689, + 8738795276227363922, + 81297770384137296, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power4 set z=x*(0,1)^(4*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power4(x *E2) *E2 { + // 258664426012969093929703085429980814127835149614277183275038967946009968870203535512256352201271898244626862047231 + b := fp.Element{ + 3203870859294639911, + 276961138506029237, + 9479726329337356593, + 13645541738420943632, + 7584832609311778094, + 101110569012358506, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue2Power5 set z=x*(0,1)^(5*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power5(x *E2) *E2 { + // 258664426012969093929703085429980814127835149614277183275038967946009968870203535512256352201271898244626862047232 + b := fp.Element{ + 12266591053191808654, + 4471292606164064357, + 295287422898805027, + 2200696361737783943, + 17292781406793965788, + 19812798628221209, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/parameters.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/parameters.go new file mode 100644 index 00000000000..6f2b1d6c7e2 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/parameters.go @@ -0,0 +1,33 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +// generator of the curve +var xGen big.Int + +var glvBasis ecc.Lattice + +func init() { + xGen.SetString("9586122913090633729", 10) + _r := fr.Modulus() + ecc.PrecomputeLattice(_r, &xGen, &glvBasis) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go new file mode 100644 index 00000000000..317f7c53541 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go @@ -0,0 +1,1297 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "encoding/binary" + "errors" + "io" + "reflect" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" +) + +// To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity +// metadata needed for point (de)compression +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// see https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/11/ +// Appendix C. ZCash serialization format for BLS12_381 +const ( + mMask byte = 0b111 << 5 + mUncompressed byte = 0b000 << 5 + _ byte = 0b001 << 5 // invalid + mUncompressedInfinity byte = 0b010 << 5 + _ byte = 0b011 << 5 // invalid + mCompressedSmallest byte = 0b100 << 5 + mCompressedLargest byte = 0b101 << 5 + mCompressedInfinity byte = 0b110 << 5 + _ byte = 0b111 << 5 // invalid +) + +// SizeOfGT represents the size in bytes that a GT element need in binary form +const SizeOfGT = fptower.SizeOfGT + +var ( + ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + ErrInvalidEncoding = errors.New("invalid point encoding") +) + +// Encoder writes bls12-377 object values to an output stream +type Encoder struct { + w io.Writer + n int64 // written bytes + raw bool // raw vs compressed encoding +} + +// Decoder reads bls12-377 object values from an inbound stream +type Decoder struct { + r io.Reader + n int64 // read bytes + subGroupCheck bool // default to true +} + +// NewDecoder returns a binary decoder supporting curve bls12-377 objects in both +// compressed and uncompressed (raw) forms +func NewDecoder(r io.Reader, options ...func(*Decoder)) *Decoder { + d := &Decoder{r: r, subGroupCheck: true} + + for _, o := range options { + o(d) + } + + return d +} + +// Decode reads the binary encoding of v from the stream +// type must be *uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, *[]G1Affine or *[]G2Affine +func (dec *Decoder) Decode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { + return errors.New("bls12-377 decoder: unsupported type, need pointer") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + // in particular, careful attention must be given to usage of Bytes() method on Elements and Points + // that return an array (not a slice) of bytes. Using this is beneficial to minimize memory allocations + // in very large (de)serialization upstream in gnark. + // (but detrimental to code readability here) + + var read64 int64 + if vf, ok := v.(io.ReaderFrom); ok { + read64, err = vf.ReadFrom(dec.r) + dec.n += read64 + return + } + + var buf [SizeOfG2AffineUncompressed]byte + var read int + var sliceLen uint32 + + switch t := v.(type) { + case *[][]uint64: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + *t = make([][]uint64, sliceLen) + + for i := range *t { + if sliceLen, err = dec.readUint32(); err != nil { + return + } + (*t)[i] = make([]uint64, sliceLen) + for j := range (*t)[i] { + if (*t)[i][j], err = dec.readUint64(); err != nil { + return + } + } + } + return + case *[]uint64: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + *t = make([]uint64, sliceLen) + for i := range *t { + if (*t)[i], err = dec.readUint64(); err != nil { + return + } + } + return + case *fr.Element: + read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + err = t.SetBytesCanonical(buf[:fr.Bytes]) + return + case *fp.Element: + read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + err = t.SetBytesCanonical(buf[:fp.Bytes]) + return + case *[]fr.Element: + read64, err = (*fr.Vector)(t).ReadFrom(dec.r) + dec.n += read64 + return + case *[]fp.Element: + read64, err = (*fp.Vector)(t).ReadFrom(dec.r) + dec.n += read64 + return + case *[][]fr.Element: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([][]fr.Element, sliceLen) + } + for i := range *t { + read64, err = (*fr.Vector)(&(*t)[i]).ReadFrom(dec.r) + dec.n += read64 + } + return + case *G1Affine: + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + } + _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) + return + case *G2Affine: + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG2AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG2AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG2AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG2AffineCompressed:SizeOfG2AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + } + _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) + return + case *[]G1Affine: + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) || *t == nil { + *t = make([]G1Affine, sliceLen) + } + compressed := make([]bool, sliceLen) + for i := 0; i < len(*t); i++ { + + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + _, err = (*t)[i].setBytes(buf[:nbBytes], false) + if err != nil { + return + } + } else { + var r bool + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { + return + } + compressed[i] = !r + } + } + var nbErrs uint64 + parallel.Execute(len(compressed), func(start, end int) { + for i := start; i < end; i++ { + if compressed[i] { + if err := (*t)[i].unsafeComputeY(dec.subGroupCheck); err != nil { + atomic.AddUint64(&nbErrs, 1) + } + } else if dec.subGroupCheck { + if !(*t)[i].IsInSubGroup() { + atomic.AddUint64(&nbErrs, 1) + } + } + } + }) + if nbErrs != 0 { + return errors.New("point decompression failed") + } + + return nil + case *[]G2Affine: + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]G2Affine, sliceLen) + } + compressed := make([]bool, sliceLen) + for i := 0; i < len(*t); i++ { + + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG2AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG2AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG2AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG2AffineCompressed:SizeOfG2AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + _, err = (*t)[i].setBytes(buf[:nbBytes], false) + if err != nil { + return + } + } else { + var r bool + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { + return + } + compressed[i] = !r + } + } + var nbErrs uint64 + parallel.Execute(len(compressed), func(start, end int) { + for i := start; i < end; i++ { + if compressed[i] { + if err := (*t)[i].unsafeComputeY(dec.subGroupCheck); err != nil { + atomic.AddUint64(&nbErrs, 1) + } + } else if dec.subGroupCheck { + if !(*t)[i].IsInSubGroup() { + atomic.AddUint64(&nbErrs, 1) + } + } + } + }) + if nbErrs != 0 { + return errors.New("point decompression failed") + } + + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New("bls12-377 encoder: unsupported type") + } + err = binary.Read(dec.r, binary.BigEndian, t) + if err == nil { + dec.n += int64(n) + } + return + } +} + +// BytesRead return total bytes read from reader +func (dec *Decoder) BytesRead() int64 { + return dec.n +} + +func (dec *Decoder) readUint32() (r uint32, err error) { + var read int + var buf [4]byte + read, err = io.ReadFull(dec.r, buf[:4]) + dec.n += int64(read) + if err != nil { + return + } + r = binary.BigEndian.Uint32(buf[:4]) + return +} + +func (dec *Decoder) readUint64() (r uint64, err error) { + var read int + var buf [8]byte + read, err = io.ReadFull(dec.r, buf[:]) + dec.n += int64(read) + if err != nil { + return + } + r = binary.BigEndian.Uint64(buf[:]) + return +} + +// isMaskInvalid returns true if the mask is invalid +func isMaskInvalid(msb byte) bool { + mData := msb & mMask + return ((mData == (0b111 << 5)) || (mData == (0b011 << 5)) || (mData == (0b001 << 5))) +} + +func isCompressed(msb byte) bool { + mData := msb & mMask + return !((mData == mUncompressed) || (mData == mUncompressedInfinity)) +} + +// NewEncoder returns a binary encoder supporting curve bls12-377 objects +func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { + // default settings + enc := &Encoder{ + w: w, + n: 0, + raw: false, + } + + // handle options + for _, option := range options { + option(enc) + } + + return enc +} + +// Encode writes the binary encoding of v to the stream +// type must be uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, []G1Affine or []G2Affine +func (enc *Encoder) Encode(v interface{}) (err error) { + if enc.raw { + return enc.encodeRaw(v) + } + return enc.encode(v) +} + +// BytesWritten return total bytes written on writer +func (enc *Encoder) BytesWritten() int64 { + return enc.n +} + +// RawEncoding returns an option to use in NewEncoder(...) which sets raw encoding mode to true +// points will not be compressed using this option +func RawEncoding() func(*Encoder) { + return func(enc *Encoder) { + enc.raw = true + } +} + +// NoSubgroupChecks returns an option to use in NewDecoder(...) which disable subgroup checks on the points +// the decoder will read. Use with caution, as crafted points from an untrusted source can lead to crypto-attacks. +func NoSubgroupChecks() func(*Decoder) { + return func(dec *Decoder) { + dec.subGroupCheck = false + } +} + +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + +func (enc *Encoder) encode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + + var written64 int64 + if vw, ok := v.(io.WriterTo); ok { + written64, err = vw.WriteTo(enc.w) + enc.n += written64 + return + } + + var written int + + switch t := v.(type) { + case []uint64: + return enc.writeUint64Slice(t) + case [][]uint64: + return enc.writeUint64SliceSlice(t) + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G2Affine: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case fr.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case fp.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case []fr.Element: + written64, err = (*fr.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case []fp.Element: + written64, err = (*fp.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case [][]fr.Element: + // write slice length + if err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))); err != nil { + return + } + enc.n += 4 + for i := range t { + written64, err = (*fr.Vector)(&t[i]).WriteTo(enc.w) + enc.n += written64 + } + return + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineCompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []G2Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG2AffineCompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} + +func (enc *Encoder) encodeRaw(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + + var written64 int64 + if vw, ok := v.(io.WriterTo); ok { + written64, err = vw.WriteTo(enc.w) + enc.n += written64 + return + } + + var written int + + switch t := v.(type) { + case []uint64: + return enc.writeUint64Slice(t) + case [][]uint64: + return enc.writeUint64SliceSlice(t) + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G2Affine: + buf := t.RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case fr.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case fp.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case []fr.Element: + written64, err = (*fr.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case []fp.Element: + written64, err = (*fp.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case [][]fr.Element: + // write slice length + if err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))); err != nil { + return + } + enc.n += 4 + for i := range t { + written64, err = (*fr.Vector)(&t[i]).WriteTo(enc.w) + enc.n += written64 + } + return + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineUncompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []G2Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG2AffineUncompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} + +func (enc *Encoder) writeUint64Slice(t []uint64) (err error) { + if err = enc.writeUint32(uint32(len(t))); err != nil { + return + } + for i := range t { + if err = enc.writeUint64(t[i]); err != nil { + return + } + } + return nil +} + +func (enc *Encoder) writeUint64SliceSlice(t [][]uint64) (err error) { + if err = enc.writeUint32(uint32(len(t))); err != nil { + return + } + for i := range t { + if err = enc.writeUint32(uint32(len(t[i]))); err != nil { + return + } + for j := range t[i] { + if err = enc.writeUint64(t[i][j]); err != nil { + return + } + } + } + return nil +} + +func (enc *Encoder) writeUint64(a uint64) error { + var buff [64 / 8]byte + binary.BigEndian.PutUint64(buff[:], a) + written, err := enc.w.Write(buff[:]) + enc.n += int64(written) + return err +} + +func (enc *Encoder) writeUint32(a uint32) error { + var buff [32 / 8]byte + binary.BigEndian.PutUint32(buff[:], a) + written, err := enc.w.Write(buff[:]) + enc.n += int64(written) + return err +} + +// SizeOfG1AffineCompressed represents the size in bytes that a G1Affine need in binary form, compressed +const SizeOfG1AffineCompressed = 48 + +// SizeOfG1AffineUncompressed represents the size in bytes that a G1Affine need in binary form, uncompressed +const SizeOfG1AffineUncompressed = SizeOfG1AffineCompressed * 2 + +// Marshal converts p to a byte slice (without point compression) +func (p *G1Affine) Marshal() []byte { + b := p.RawBytes() + return b[:] +} + +// Unmarshal is an alias to SetBytes() +func (p *G1Affine) Unmarshal(buf []byte) error { + _, err := p.SetBytes(buf) + return err +} + +// Bytes returns binary representation of p +// will store X coordinate in regular form and a parity bit +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// +// The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. +// +// The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. +// +// The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. +func (p *G1Affine) Bytes() (res [SizeOfG1AffineCompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + res[0] = mCompressedInfinity + return + } + + msbMask := mCompressedSmallest + // compressed, we need to know if Y is lexicographically bigger than -Y + // if p.Y ">" -p.Y + if p.Y.LexicographicallyLargest() { + msbMask = mCompressedLargest + } + + // we store X and mask the most significant word with our metadata mask + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + + res[0] |= msbMask + + return +} + +// RawBytes returns binary representation of p (stores X and Y coordinate) +// see Bytes() for a compressed representation +func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + + res[0] = mUncompressedInfinity + + return + } + + // not compressed + // we store the Y coordinate + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.Y) + + // we store X and mask the most significant word with our metadata mask + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + + res[0] |= mUncompressed + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// +// bytes in buf must match either RawBytes() or Bytes() output +// +// if buf is too short io.ErrShortBuffer is returned +// +// if buf contains compressed representation (output from Bytes()) and we're unable to compute +// the Y coordinate (i.e the square root doesn't exist) this function returns an error +// +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G1Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG1AffineCompressed { + return 0, io.ErrShortBuffer + } + + // most significant byte + mData := buf[0] & mMask + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(mData) { + return 0, ErrInvalidEncoding + } + + // check buffer size + if (mData == mUncompressed) || (mData == mUncompressedInfinity) { + if len(buf) < SizeOfG1AffineUncompressed { + return 0, io.ErrShortBuffer + } + } + + // infinity encoded, we still check that the buffer is full of zeroes. + if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG1AffineCompressed, nil + } + if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG1AffineUncompressed, nil + } + + // uncompressed point + if mData == mUncompressed { + // read X and Y coordinates + if err := p.X.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.Y.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineUncompressed, nil + } + + // we have a compressed coordinate + // we need to + // 1. copy the buffer (to keep this method thread safe) + // 2. we need to solve the curve equation to compute Y + + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return 0, err + } + + var YSquared, Y fp.Element + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { + return 0, errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineCompressed, nil +} + +// unsafeComputeY called by Decoder when processing slices of compressed point in parallel (step 2) +// it computes the Y coordinate from the already set X coordinate and is compute intensive +func (p *G1Affine) unsafeComputeY(subGroupCheck bool) error { + // stored in unsafeSetCompressedBytes + + mData := byte(p.Y[0]) + + // we have a compressed coordinate, we need to solve the curve equation to compute Y + var YSquared, Y fp.Element + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { + return errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return errors.New("invalid point: subgroup check failed") + } + + return nil +} + +// unsafeSetCompressedBytes is called by Decoder when processing slices of compressed point in parallel (step 1) +// assumes buf[:8] mask is set to compressed +// returns true if point is infinity and need no further processing +// it sets X coordinate and uses Y for scratch space to store decompression metadata +func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err error) { + + // read the most significant byte + mData := buf[0] & mMask + + if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return isInfinity, nil + } + + // we need to copy the input buffer (to keep this method thread safe) + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return false, err + } + // store mData in p.Y[0] + p.Y[0] = uint64(mData) + + // recomputing Y will be done asynchronously + return isInfinity, nil +} + +// SizeOfG2AffineCompressed represents the size in bytes that a G2Affine need in binary form, compressed +const SizeOfG2AffineCompressed = 48 * 2 + +// SizeOfG2AffineUncompressed represents the size in bytes that a G2Affine need in binary form, uncompressed +const SizeOfG2AffineUncompressed = SizeOfG2AffineCompressed * 2 + +// Marshal converts p to a byte slice (without point compression) +func (p *G2Affine) Marshal() []byte { + b := p.RawBytes() + return b[:] +} + +// Unmarshal is an alias to SetBytes() +func (p *G2Affine) Unmarshal(buf []byte) error { + _, err := p.SetBytes(buf) + return err +} + +// Bytes returns binary representation of p +// will store X coordinate in regular form and a parity bit +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// +// The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. +// +// The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. +// +// The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. +func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + res[0] = mCompressedInfinity + return + } + + msbMask := mCompressedSmallest + // compressed, we need to know if Y is lexicographically bigger than -Y + // if p.Y ">" -p.Y + if p.Y.LexicographicallyLargest() { + msbMask = mCompressedLargest + } + + // we store X and mask the most significant word with our metadata mask + // p.X.A1 | p.X.A0 + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.X.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) + + res[0] |= msbMask + + return +} + +// RawBytes returns binary representation of p (stores X and Y coordinate) +// see Bytes() for a compressed representation +func (p *G2Affine) RawBytes() (res [SizeOfG2AffineUncompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + + res[0] = mUncompressedInfinity + + return + } + + // not compressed + // we store the Y coordinate + // p.Y.A1 | p.Y.A0 + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[144:144+fp.Bytes]), p.Y.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[96:96+fp.Bytes]), p.Y.A1) + + // we store X and mask the most significant word with our metadata mask + // p.X.A1 | p.X.A0 + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.X.A0) + + res[0] |= mUncompressed + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// +// bytes in buf must match either RawBytes() or Bytes() output +// +// if buf is too short io.ErrShortBuffer is returned +// +// if buf contains compressed representation (output from Bytes()) and we're unable to compute +// the Y coordinate (i.e the square root doesn't exist) this function returns an error +// +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G2Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG2AffineCompressed { + return 0, io.ErrShortBuffer + } + + // most significant byte + mData := buf[0] & mMask + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(mData) { + return 0, ErrInvalidEncoding + } + + // check buffer size + if (mData == mUncompressed) || (mData == mUncompressedInfinity) { + if len(buf) < SizeOfG2AffineUncompressed { + return 0, io.ErrShortBuffer + } + } + + // infinity encoded, we still check that the buffer is full of zeroes. + if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG2AffineCompressed, nil + } + if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG2AffineUncompressed, nil + } + + // uncompressed point + if mData == mUncompressed { + // read X and Y coordinates + // p.X.A1 | p.X.A0 + if err := p.X.A1.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + // p.Y.A1 | p.Y.A0 + if err := p.Y.A1.SetBytesCanonical(buf[fp.Bytes*2 : fp.Bytes*3]); err != nil { + return 0, err + } + if err := p.Y.A0.SetBytesCanonical(buf[fp.Bytes*3 : fp.Bytes*4]); err != nil { + return 0, err + } + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG2AffineUncompressed, nil + } + + // we have a compressed coordinate + // we need to + // 1. copy the buffer (to keep this method thread safe) + // 2. we need to solve the curve equation to compute Y + + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + // p.X.A1 | p.X.A0 + if err := p.X.A1.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + + var YSquared, Y fptower.E2 + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bTwistCurveCoeff) + if YSquared.Legendre() == -1 { + return 0, errors.New("invalid compressed coordinate: square root doesn't exist") + } + Y.Sqrt(&YSquared) + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG2AffineCompressed, nil +} + +// unsafeComputeY called by Decoder when processing slices of compressed point in parallel (step 2) +// it computes the Y coordinate from the already set X coordinate and is compute intensive +func (p *G2Affine) unsafeComputeY(subGroupCheck bool) error { + // stored in unsafeSetCompressedBytes + + mData := byte(p.Y.A0[0]) + + // we have a compressed coordinate, we need to solve the curve equation to compute Y + var YSquared, Y fptower.E2 + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bTwistCurveCoeff) + if YSquared.Legendre() == -1 { + return errors.New("invalid compressed coordinate: square root doesn't exist") + } + Y.Sqrt(&YSquared) + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return errors.New("invalid point: subgroup check failed") + } + + return nil +} + +// unsafeSetCompressedBytes is called by Decoder when processing slices of compressed point in parallel (step 1) +// assumes buf[:8] mask is set to compressed +// returns true if point is infinity and need no further processing +// it sets X coordinate and uses Y for scratch space to store decompression metadata +func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err error) { + + // read the most significant byte + mData := buf[0] & mMask + + if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return isInfinity, nil + } + + // we need to copy the input buffer (to keep this method thread safe) + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + // p.X.A1 | p.X.A0 + if err := p.X.A1.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return false, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return false, err + } + + // store mData in p.Y.A0[0] + p.Y.A0[0] = uint64(mData) + + // recomputing Y will be done asynchronously + return isInfinity, nil +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go new file mode 100644 index 00000000000..8ae82e0a3bd --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go @@ -0,0 +1,813 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "errors" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/internal/parallel" + "math" + "runtime" +) + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Affine, error) { + var _p G1Jac + if _, err := _p.MultiExp(points, scalars, config); err != nil { + return nil, err + } + p.FromJacobian(&_p) + return p, nil +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Jac, error) { + // TODO @gbotrel replace the ecc.MultiExpConfig by a Option pattern for maintainability. + // note: + // each of the msmCX method is the same, except for the c constant it declares + // duplicating (through template generation) these methods allows to declare the buckets on the stack + // the choice of c needs to be improved: + // there is a theoretical value that gives optimal asymptotics + // but in practice, other factors come into play, including: + // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 + // * number of CPUs + // * cache friendliness (which depends on the host, G1 or G2... ) + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + + // for each msmCX + // step 1 + // we compute, for each scalars over c-bit wide windows, nbChunk digits + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + // negative digits will be processed in the next step as adding -G into the bucket instead of G + // (computing -G is cheap, and this saves us half of the buckets) + // step 2 + // buckets are declared on the stack + // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) + // we use jacobian extended formulas here as they are faster than mixed addition + // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel + // step 3 + // reduce the buckets weighed sums into our result (msmReduceChunk) + + // ensure len(points) == len(scalars) + nbPoints := len(points) + if nbPoints != len(scalars) { + return nil, errors.New("len(points) != len(scalars)") + } + + // if nbTasks is not set, use all available CPUs + if config.NbTasks <= 0 { + config.NbTasks = runtime.NumCPU() * 2 + } else if config.NbTasks > 1024 { + return nil, errors.New("invalid config: config.NbTasks > 1024") + } + + // here, we compute the best C for nbPoints + // we split recursively until nbChunks(c) >= nbTasks, + bestC := func(nbPoints int) uint64 { + // implemented msmC methods (the c we use must be in this slice) + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + var C uint64 + // approximate cost (in group operations) + // cost = bits/c * (nbPoints + 2^{c}) + // this needs to be verified empirically. + // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results + min := math.MaxFloat64 + for _, c := range implementedCs { + cc := (fr.Bits + 1) * (nbPoints + (1 << c)) + cost := float64(cc) / float64(c) + if cost < min { + min = cost + C = c + } + } + return C + } + + C := bestC(nbPoints) + nbChunks := int(computeNbChunks(C)) + + // should we recursively split the msm in half? (see below) + // we want to minimize the execution time of the algorithm; + // splitting the msm will **add** operations, but if it allows to use more CPU, it might be worth it. + + // costFunction returns a metric that represent the "wall time" of the algorithm + costFunction := func(nbTasks, nbCpus, costPerTask int) int { + // cost for the reduction of all tasks (msmReduceChunk) + totalCost := nbTasks + + // cost for the computation of each task (msmProcessChunk) + for nbTasks >= nbCpus { + nbTasks -= nbCpus + totalCost += costPerTask + } + if nbTasks > 0 { + totalCost += costPerTask + } + return totalCost + } + + // costPerTask is the approximate number of group ops per task + costPerTask := func(c uint64, nbPoints int) int { return (nbPoints + int((1 << c))) } + + costPreSplit := costFunction(nbChunks, config.NbTasks, costPerTask(C, nbPoints)) + + cPostSplit := bestC(nbPoints / 2) + nbChunksPostSplit := int(computeNbChunks(cPostSplit)) + costPostSplit := costFunction(nbChunksPostSplit*2, config.NbTasks, costPerTask(cPostSplit, nbPoints/2)) + + // if the cost of the split msm is lower than the cost of the non split msm, we split + if costPostSplit < costPreSplit { + config.NbTasks = int(math.Ceil(float64(config.NbTasks) / 2.0)) + var _p G1Jac + chDone := make(chan struct{}, 1) + go func() { + _p.MultiExp(points[:nbPoints/2], scalars[:nbPoints/2], config) + close(chDone) + }() + p.MultiExp(points[nbPoints/2:], scalars[nbPoints/2:], config) + <-chDone + p.AddAssign(&_p) + return p, nil + } + + // if we don't split, we use the best C we found + _innerMsmG1(p, C, points, scalars, config) + + return p, nil +} + +func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) *G1Jac { + // partition the scalars + digits, chunkStats := partitionScalars(scalars, c, config.NbTasks) + + nbChunks := computeNbChunks(c) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack and this is critical for performance + + // each go routine sends its result in chChunks[i] channel + chChunks := make([]chan g1JacExtended, nbChunks) + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // we use a semaphore to limit the number of go routines running concurrently + // (only if nbTasks < nbCPU) + var sem chan struct{} + if config.NbTasks < runtime.NumCPU() { + // we add nbChunks because if chunk is overweight we split it in two + sem = make(chan struct{}, config.NbTasks+int(nbChunks)) + for i := 0; i < config.NbTasks; i++ { + sem <- struct{}{} + } + defer func() { + close(sem) + }() + } + + // the last chunk may be processed with a different method than the rest, as it could be smaller. + n := len(points) + for j := int(nbChunks - 1); j >= 0; j-- { + processChunk := getChunkProcessorG1(c, chunkStats[j]) + if j == int(nbChunks-1) { + processChunk = getChunkProcessorG1(lastC(c), chunkStats[j]) + } + if chunkStats[j].weight >= 115 { + // we split this in more go routines since this chunk has more work to do than the others. + // else what would happen is this go routine would finish much later than the others. + chSplit := make(chan g1JacExtended, 2) + split := n / 2 + + if sem != nil { + sem <- struct{}{} // add another token to the semaphore, since we split in two. + } + go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split], sem) + go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n], sem) + go func(chunkID int) { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[chunkID] <- s1 + }(j) + continue + } + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) + } + + return msmReduceChunkG1Affine(p, int(c), chChunks[:]) +} + +// getChunkProcessorG1 decides, depending on c window size and statistics for the chunk +// to return the best algorithm to process the chunk. +func getChunkProcessorG1(c uint64, stat chunkStat) func(chunkID uint64, chRes chan<- g1JacExtended, c uint64, points []G1Affine, digits []uint16, sem chan struct{}) { + switch c { + + case 2: + return processChunkG1Jacobian[bucketg1JacExtendedC2] + case 4: + return processChunkG1Jacobian[bucketg1JacExtendedC4] + case 5: + return processChunkG1Jacobian[bucketg1JacExtendedC5] + case 6: + return processChunkG1Jacobian[bucketg1JacExtendedC6] + case 7: + return processChunkG1Jacobian[bucketg1JacExtendedC7] + case 8: + return processChunkG1Jacobian[bucketg1JacExtendedC8] + case 9: + return processChunkG1Jacobian[bucketg1JacExtendedC9] + case 10: + const batchSize = 80 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC10] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC10, bucketG1AffineC10, bitSetC10, pG1AffineC10, ppG1AffineC10, qG1AffineC10, cG1AffineC10] + case 11: + const batchSize = 150 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC11] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC11, bucketG1AffineC11, bitSetC11, pG1AffineC11, ppG1AffineC11, qG1AffineC11, cG1AffineC11] + case 12: + const batchSize = 200 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC12] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC12, bucketG1AffineC12, bitSetC12, pG1AffineC12, ppG1AffineC12, qG1AffineC12, cG1AffineC12] + case 13: + const batchSize = 350 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC13] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC13, bucketG1AffineC13, bitSetC13, pG1AffineC13, ppG1AffineC13, qG1AffineC13, cG1AffineC13] + case 14: + const batchSize = 400 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC14] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC14, bucketG1AffineC14, bitSetC14, pG1AffineC14, ppG1AffineC14, qG1AffineC14, cG1AffineC14] + case 15: + const batchSize = 500 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC15] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC15, bucketG1AffineC15, bitSetC15, pG1AffineC15, ppG1AffineC15, qG1AffineC15, cG1AffineC15] + case 16: + const batchSize = 640 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC16] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC16, bucketG1AffineC16, bitSetC16, pG1AffineC16, ppG1AffineC16, qG1AffineC16, cG1AffineC16] + default: + // panic("will not happen c != previous values is not generated by templates") + return processChunkG1Jacobian[bucketg1JacExtendedC16] + } +} + +// msmReduceChunkG1Affine reduces the weighted sum of the buckets into the result of the multiExp +func msmReduceChunkG1Affine(p *G1Jac, c int, chChunks []chan g1JacExtended) *G1Jac { + var _p g1JacExtended + totalj := <-chChunks[len(chChunks)-1] + _p.Set(&totalj) + for j := len(chChunks) - 2; j >= 0; j-- { + for l := 0; l < c; l++ { + _p.double(&_p) + } + totalj := <-chChunks[j] + _p.add(&totalj) + } + + return p.unsafeFromJacExtended(&_p) +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Affine, error) { + var _p G2Jac + if _, err := _p.MultiExp(points, scalars, config); err != nil { + return nil, err + } + p.FromJacobian(&_p) + return p, nil +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Jac, error) { + // TODO @gbotrel replace the ecc.MultiExpConfig by a Option pattern for maintainability. + // note: + // each of the msmCX method is the same, except for the c constant it declares + // duplicating (through template generation) these methods allows to declare the buckets on the stack + // the choice of c needs to be improved: + // there is a theoretical value that gives optimal asymptotics + // but in practice, other factors come into play, including: + // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 + // * number of CPUs + // * cache friendliness (which depends on the host, G1 or G2... ) + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + + // for each msmCX + // step 1 + // we compute, for each scalars over c-bit wide windows, nbChunk digits + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + // negative digits will be processed in the next step as adding -G into the bucket instead of G + // (computing -G is cheap, and this saves us half of the buckets) + // step 2 + // buckets are declared on the stack + // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) + // we use jacobian extended formulas here as they are faster than mixed addition + // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel + // step 3 + // reduce the buckets weighed sums into our result (msmReduceChunk) + + // ensure len(points) == len(scalars) + nbPoints := len(points) + if nbPoints != len(scalars) { + return nil, errors.New("len(points) != len(scalars)") + } + + // if nbTasks is not set, use all available CPUs + if config.NbTasks <= 0 { + config.NbTasks = runtime.NumCPU() * 2 + } else if config.NbTasks > 1024 { + return nil, errors.New("invalid config: config.NbTasks > 1024") + } + + // here, we compute the best C for nbPoints + // we split recursively until nbChunks(c) >= nbTasks, + bestC := func(nbPoints int) uint64 { + // implemented msmC methods (the c we use must be in this slice) + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + var C uint64 + // approximate cost (in group operations) + // cost = bits/c * (nbPoints + 2^{c}) + // this needs to be verified empirically. + // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results + min := math.MaxFloat64 + for _, c := range implementedCs { + cc := (fr.Bits + 1) * (nbPoints + (1 << c)) + cost := float64(cc) / float64(c) + if cost < min { + min = cost + C = c + } + } + return C + } + + C := bestC(nbPoints) + nbChunks := int(computeNbChunks(C)) + + // should we recursively split the msm in half? (see below) + // we want to minimize the execution time of the algorithm; + // splitting the msm will **add** operations, but if it allows to use more CPU, it might be worth it. + + // costFunction returns a metric that represent the "wall time" of the algorithm + costFunction := func(nbTasks, nbCpus, costPerTask int) int { + // cost for the reduction of all tasks (msmReduceChunk) + totalCost := nbTasks + + // cost for the computation of each task (msmProcessChunk) + for nbTasks >= nbCpus { + nbTasks -= nbCpus + totalCost += costPerTask + } + if nbTasks > 0 { + totalCost += costPerTask + } + return totalCost + } + + // costPerTask is the approximate number of group ops per task + costPerTask := func(c uint64, nbPoints int) int { return (nbPoints + int((1 << c))) } + + costPreSplit := costFunction(nbChunks, config.NbTasks, costPerTask(C, nbPoints)) + + cPostSplit := bestC(nbPoints / 2) + nbChunksPostSplit := int(computeNbChunks(cPostSplit)) + costPostSplit := costFunction(nbChunksPostSplit*2, config.NbTasks, costPerTask(cPostSplit, nbPoints/2)) + + // if the cost of the split msm is lower than the cost of the non split msm, we split + if costPostSplit < costPreSplit { + config.NbTasks = int(math.Ceil(float64(config.NbTasks) / 2.0)) + var _p G2Jac + chDone := make(chan struct{}, 1) + go func() { + _p.MultiExp(points[:nbPoints/2], scalars[:nbPoints/2], config) + close(chDone) + }() + p.MultiExp(points[nbPoints/2:], scalars[nbPoints/2:], config) + <-chDone + p.AddAssign(&_p) + return p, nil + } + + // if we don't split, we use the best C we found + _innerMsmG2(p, C, points, scalars, config) + + return p, nil +} + +func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) *G2Jac { + // partition the scalars + digits, chunkStats := partitionScalars(scalars, c, config.NbTasks) + + nbChunks := computeNbChunks(c) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack and this is critical for performance + + // each go routine sends its result in chChunks[i] channel + chChunks := make([]chan g2JacExtended, nbChunks) + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // we use a semaphore to limit the number of go routines running concurrently + // (only if nbTasks < nbCPU) + var sem chan struct{} + if config.NbTasks < runtime.NumCPU() { + // we add nbChunks because if chunk is overweight we split it in two + sem = make(chan struct{}, config.NbTasks+int(nbChunks)) + for i := 0; i < config.NbTasks; i++ { + sem <- struct{}{} + } + defer func() { + close(sem) + }() + } + + // the last chunk may be processed with a different method than the rest, as it could be smaller. + n := len(points) + for j := int(nbChunks - 1); j >= 0; j-- { + processChunk := getChunkProcessorG2(c, chunkStats[j]) + if j == int(nbChunks-1) { + processChunk = getChunkProcessorG2(lastC(c), chunkStats[j]) + } + if chunkStats[j].weight >= 115 { + // we split this in more go routines since this chunk has more work to do than the others. + // else what would happen is this go routine would finish much later than the others. + chSplit := make(chan g2JacExtended, 2) + split := n / 2 + + if sem != nil { + sem <- struct{}{} // add another token to the semaphore, since we split in two. + } + go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split], sem) + go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n], sem) + go func(chunkID int) { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[chunkID] <- s1 + }(j) + continue + } + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) + } + + return msmReduceChunkG2Affine(p, int(c), chChunks[:]) +} + +// getChunkProcessorG2 decides, depending on c window size and statistics for the chunk +// to return the best algorithm to process the chunk. +func getChunkProcessorG2(c uint64, stat chunkStat) func(chunkID uint64, chRes chan<- g2JacExtended, c uint64, points []G2Affine, digits []uint16, sem chan struct{}) { + switch c { + + case 2: + return processChunkG2Jacobian[bucketg2JacExtendedC2] + case 4: + return processChunkG2Jacobian[bucketg2JacExtendedC4] + case 5: + return processChunkG2Jacobian[bucketg2JacExtendedC5] + case 6: + return processChunkG2Jacobian[bucketg2JacExtendedC6] + case 7: + return processChunkG2Jacobian[bucketg2JacExtendedC7] + case 8: + return processChunkG2Jacobian[bucketg2JacExtendedC8] + case 9: + return processChunkG2Jacobian[bucketg2JacExtendedC9] + case 10: + const batchSize = 80 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC10] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC10, bucketG2AffineC10, bitSetC10, pG2AffineC10, ppG2AffineC10, qG2AffineC10, cG2AffineC10] + case 11: + const batchSize = 150 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC11] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC11, bucketG2AffineC11, bitSetC11, pG2AffineC11, ppG2AffineC11, qG2AffineC11, cG2AffineC11] + case 12: + const batchSize = 200 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC12] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC12, bucketG2AffineC12, bitSetC12, pG2AffineC12, ppG2AffineC12, qG2AffineC12, cG2AffineC12] + case 13: + const batchSize = 350 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC13] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC13, bucketG2AffineC13, bitSetC13, pG2AffineC13, ppG2AffineC13, qG2AffineC13, cG2AffineC13] + case 14: + const batchSize = 400 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC14] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC14, bucketG2AffineC14, bitSetC14, pG2AffineC14, ppG2AffineC14, qG2AffineC14, cG2AffineC14] + case 15: + const batchSize = 500 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC15] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC15, bucketG2AffineC15, bitSetC15, pG2AffineC15, ppG2AffineC15, qG2AffineC15, cG2AffineC15] + case 16: + const batchSize = 640 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC16] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC16, bucketG2AffineC16, bitSetC16, pG2AffineC16, ppG2AffineC16, qG2AffineC16, cG2AffineC16] + default: + // panic("will not happen c != previous values is not generated by templates") + return processChunkG2Jacobian[bucketg2JacExtendedC16] + } +} + +// msmReduceChunkG2Affine reduces the weighted sum of the buckets into the result of the multiExp +func msmReduceChunkG2Affine(p *G2Jac, c int, chChunks []chan g2JacExtended) *G2Jac { + var _p g2JacExtended + totalj := <-chChunks[len(chChunks)-1] + _p.Set(&totalj) + for j := len(chChunks) - 2; j >= 0; j-- { + for l := 0; l < c; l++ { + _p.double(&_p) + } + totalj := <-chChunks[j] + _p.add(&totalj) + } + + return p.unsafeFromJacExtended(&_p) +} + +// selector stores the index, mask and shifts needed to select bits from a scalar +// it is used during the multiExp algorithm or the batch scalar multiplication +type selector struct { + index uint64 // index in the multi-word scalar to select bits from + mask uint64 // mask (c-bit wide) + shift uint64 // shift needed to get our bits on low positions + + multiWordSelect bool // set to true if we need to select bits from 2 words (case where c doesn't divide 64) + maskHigh uint64 // same than mask, for index+1 + shiftHigh uint64 // same than shift, for index+1 +} + +// return number of chunks for a given window size c +// the last chunk may be bigger to accommodate a potential carry from the NAF decomposition +func computeNbChunks(c uint64) uint64 { + return (fr.Bits + c - 1) / c +} + +// return the last window size for a scalar; +// this last window should accommodate a carry (from the NAF decomposition) +// it can be == c if we have 1 available bit +// it can be > c if we have 0 available bit +// it can be < c if we have 2+ available bits +func lastC(c uint64) uint64 { + nbAvailableBits := (computeNbChunks(c) * c) - fr.Bits + return c + 1 - nbAvailableBits +} + +type chunkStat struct { + // relative weight of work compared to other chunks. 100.0 -> nominal weight. + weight float32 + + // percentage of bucket filled in the window; + ppBucketFilled float32 + nbBucketFilled int +} + +// partitionScalars compute, for each scalars over c-bit wide windows, nbChunk digits +// if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract +// 2^{c} to the current digit, making it negative. +// negative digits can be processed in a later step as adding -G into the bucket instead of G +// (computing -G is cheap, and this saves us half of the buckets in the MultiExp or BatchScalarMultiplication) +func partitionScalars(scalars []fr.Element, c uint64, nbTasks int) ([]uint16, []chunkStat) { + // no benefit here to have more tasks than CPUs + if nbTasks > runtime.NumCPU() { + nbTasks = runtime.NumCPU() + } + + // number of c-bit radixes in a scalar + nbChunks := computeNbChunks(c) + + digits := make([]uint16, len(scalars)*int(nbChunks)) + + mask := uint64((1 << c) - 1) // low c bits are 1 + max := int(1<<(c-1)) - 1 // max value (inclusive) we want for our digits + cDivides64 := (64 % c) == 0 // if c doesn't divide 64, we may need to select over multiple words + + // compute offset and word selector / shift to select the right bits of our windows + selectors := make([]selector, nbChunks) + for chunk := uint64(0); chunk < nbChunks; chunk++ { + jc := uint64(chunk * c) + d := selector{} + d.index = jc / 64 + d.shift = jc - (d.index * 64) + d.mask = mask << d.shift + d.multiWordSelect = !cDivides64 && d.shift > (64-c) && d.index < (fr.Limbs-1) + if d.multiWordSelect { + nbBitsHigh := d.shift - uint64(64-c) + d.maskHigh = (1 << nbBitsHigh) - 1 + d.shiftHigh = (c - nbBitsHigh) + } + selectors[chunk] = d + } + + parallel.Execute(len(scalars), func(start, end int) { + for i := start; i < end; i++ { + if scalars[i].IsZero() { + // everything is 0, no need to process this scalar + continue + } + scalar := scalars[i].Bits() + + var carry int + + // for each chunk in the scalar, compute the current digit, and an eventual carry + for chunk := uint64(0); chunk < nbChunks-1; chunk++ { + s := selectors[chunk] + + // init with carry if any + digit := carry + carry = 0 + + // digit = value of the c-bit window + digit += int((scalar[s.index] & s.mask) >> s.shift) + + if s.multiWordSelect { + // we are selecting bits over 2 words + digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh + } + + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + if digit > max { + digit -= (1 << c) + carry = 1 + } + + // if digit is zero, no impact on result + if digit == 0 { + continue + } + + var bits uint16 + if digit > 0 { + bits = uint16(digit) << 1 + } else { + bits = (uint16(-digit-1) << 1) + 1 + } + digits[int(chunk)*len(scalars)+i] = bits + } + + // for the last chunk, we don't want to borrow from a next window + // (but may have a larger max value) + chunk := nbChunks - 1 + s := selectors[chunk] + // init with carry if any + digit := carry + // digit = value of the c-bit window + digit += int((scalar[s.index] & s.mask) >> s.shift) + if s.multiWordSelect { + // we are selecting bits over 2 words + digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh + } + digits[int(chunk)*len(scalars)+i] = uint16(digit) << 1 + } + + }, nbTasks) + + // aggregate chunk stats + chunkStats := make([]chunkStat, nbChunks) + if c <= 9 { + // no need to compute stats for small window sizes + return digits, chunkStats + } + parallel.Execute(len(chunkStats), func(start, end int) { + // for each chunk compute the statistics + for chunkID := start; chunkID < end; chunkID++ { + // indicates if a bucket is hit. + var b bitSetC16 + + // digits for the chunk + chunkDigits := digits[chunkID*len(scalars) : (chunkID+1)*len(scalars)] + + totalOps := 0 + nz := 0 // non zero buckets count + for _, digit := range chunkDigits { + if digit == 0 { + continue + } + totalOps++ + bucketID := digit >> 1 + if digit&1 == 0 { + bucketID -= 1 + } + if !b[bucketID] { + nz++ + b[bucketID] = true + } + } + chunkStats[chunkID].weight = float32(totalOps) // count number of ops for now, we will compute the weight after + chunkStats[chunkID].ppBucketFilled = (float32(nz) * 100.0) / float32(int(1<<(c-1))) + chunkStats[chunkID].nbBucketFilled = nz + } + }, nbTasks) + + totalOps := float32(0.0) + for _, stat := range chunkStats { + totalOps += stat.weight + } + + target := totalOps / float32(nbChunks) + if target != 0.0 { + // if target == 0, it means all the scalars are 0 everywhere, there is no work to be done. + for i := 0; i < len(chunkStats); i++ { + chunkStats[i].weight = (chunkStats[i].weight * 100.0) / target + } + } + + return digits, chunkStats +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_affine.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_affine.go new file mode 100644 index 00000000000..422862c77a4 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_affine.go @@ -0,0 +1,710 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" +) + +type batchOpG1Affine struct { + bucketID uint16 + point G1Affine +} + +// processChunkG1BatchAffine process a chunk of the scalars during the msm +// using affine coordinates for the buckets. To amortize the cost of the inverse in the affine addition +// we use a batch affine addition. +// +// this is derived from a PR by 0x0ece : https://github.com/ConsenSys/gnark-crypto/pull/249 +// See Section 5.3: ia.cr/2022/1396 +func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP pG1Affine, TPP ppG1Affine, TQ qOpsG1Affine, TC cG1Affine]( + chunk uint64, + chRes chan<- g1JacExtended, + c uint64, + points []G1Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + // the batch affine addition needs independent points; in other words, for a window of batchSize + // we want to hit independent bucketIDs when processing the digit. if there is a conflict (we're trying + // to add 2 different points to the same bucket), then we push the conflicted point to a queue. + // each time the batch is full, we execute it, and tentatively put the points (if not conflict) + // from the top of the queue into the next batch. + // if the queue is full, we "flush it"; we sequentially add the points to the buckets in + // g1JacExtended coordinates. + // The reasoning behind this is the following; batchSize is chosen such as, for a uniformly random + // input, the number of conflicts is going to be low, and the element added to the queue should be immediately + // processed in the next batch. If it's not the case, then our inputs are not random; and we fallback to + // non-batch-affine version. + + // note that we have 2 sets of buckets + // 1 in G1Affine used with the batch affine additions + // 1 in g1JacExtended used in case the queue of conflicting points + var buckets B + var bucketsJE BJE + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + bucketsJE[i].setInfinity() + } + + // setup for the batch affine; + var ( + bucketIds BS // bitSet to signify presence of a bucket in current batch + cptAdd int // count the number of bucket + point added to current batch + R TPP // bucket references + P TP // points to be added to R (buckets); it is beneficial to store them on the stack (ie copy) + queue TQ // queue of points that conflict the current batch + qID int // current position in queue + ) + + batchSize := len(P) + + isFull := func() bool { return cptAdd == batchSize } + + executeAndReset := func() { + batchAddG1Affine[TP, TPP, TC](&R, &P, cptAdd) + var tmp BS + bucketIds = tmp + cptAdd = 0 + } + + addFromQueue := func(op batchOpG1Affine) { + // @precondition: must ensures bucket is not "used" in current batch + // note that there is a bit of duplicate logic between add and addFromQueue + // the reason is that as of Go 1.19.3, if we pass a pointer to the queue item (see add signature) + // the compiler will put the queue on the heap. + BK := &buckets[op.bucketID] + + // handle special cases with inf or -P / P + if BK.IsInfinity() { + BK.Set(&op.point) + return + } + if BK.X.Equal(&op.point.X) { + if BK.Y.Equal(&op.point.Y) { + // P + P: doubling, which should be quite rare -- + // we use the other set of buckets + bucketsJE[op.bucketID].addMixed(&op.point) + return + } + BK.setInfinity() + return + } + + bucketIds[op.bucketID] = true + R[cptAdd] = BK + P[cptAdd] = op.point + cptAdd++ + } + + add := func(bucketID uint16, PP *G1Affine, isAdd bool) { + // @precondition: ensures bucket is not "used" in current batch + BK := &buckets[bucketID] + // handle special cases with inf or -P / P + if BK.IsInfinity() { + if isAdd { + BK.Set(PP) + } else { + BK.Neg(PP) + } + return + } + if BK.X.Equal(&PP.X) { + if BK.Y.Equal(&PP.Y) { + // P + P: doubling, which should be quite rare -- + if isAdd { + bucketsJE[bucketID].addMixed(PP) + } else { + BK.setInfinity() + } + return + } + if isAdd { + BK.setInfinity() + } else { + bucketsJE[bucketID].subMixed(PP) + } + return + } + + bucketIds[bucketID] = true + R[cptAdd] = BK + if isAdd { + P[cptAdd].Set(PP) + } else { + P[cptAdd].Neg(PP) + } + cptAdd++ + } + + flushQueue := func() { + for i := 0; i < qID; i++ { + bucketsJE[queue[i].bucketID].addMixed(&queue[i].point) + } + qID = 0 + } + + processTopQueue := func() { + for i := qID - 1; i >= 0; i-- { + if bucketIds[queue[i].bucketID] { + return + } + addFromQueue(queue[i]) + // len(queue) < batchSize so no need to check for full batch. + qID-- + } + } + + for i, digit := range digits { + + if digit == 0 || points[i].IsInfinity() { + continue + } + + bucketID := uint16((digit >> 1)) + isAdd := digit&1 == 0 + if isAdd { + // add + bucketID -= 1 + } + + if bucketIds[bucketID] { + // put it in queue + queue[qID].bucketID = bucketID + if isAdd { + queue[qID].point.Set(&points[i]) + } else { + queue[qID].point.Neg(&points[i]) + } + qID++ + + // queue is full, flush it. + if qID == len(queue)-1 { + flushQueue() + } + continue + } + + // we add the point to the batch. + add(bucketID, &points[i], isAdd) + if isFull() { + executeAndReset() + processTopQueue() + } + } + + // flush items in batch. + executeAndReset() + + // empty the queue + flushQueue() + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + var runningSum, total g1JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + runningSum.addMixed(&buckets[k]) + if !bucketsJE[k].IsZero() { + runningSum.add(&bucketsJE[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total + +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketG1AffineC10 [512]G1Affine +type bucketG1AffineC11 [1024]G1Affine +type bucketG1AffineC12 [2048]G1Affine +type bucketG1AffineC13 [4096]G1Affine +type bucketG1AffineC14 [8192]G1Affine +type bucketG1AffineC15 [16384]G1Affine +type bucketG1AffineC16 [32768]G1Affine + +// buckets: array of G1Affine points of size 1 << (c-1) +type ibG1Affine interface { + bucketG1AffineC10 | + bucketG1AffineC11 | + bucketG1AffineC12 | + bucketG1AffineC13 | + bucketG1AffineC14 | + bucketG1AffineC15 | + bucketG1AffineC16 +} + +// array of coordinates fp.Element +type cG1Affine interface { + cG1AffineC10 | + cG1AffineC11 | + cG1AffineC12 | + cG1AffineC13 | + cG1AffineC14 | + cG1AffineC15 | + cG1AffineC16 +} + +// buckets: array of G1Affine points (for the batch addition) +type pG1Affine interface { + pG1AffineC10 | + pG1AffineC11 | + pG1AffineC12 | + pG1AffineC13 | + pG1AffineC14 | + pG1AffineC15 | + pG1AffineC16 +} + +// buckets: array of *G1Affine points (for the batch addition) +type ppG1Affine interface { + ppG1AffineC10 | + ppG1AffineC11 | + ppG1AffineC12 | + ppG1AffineC13 | + ppG1AffineC14 | + ppG1AffineC15 | + ppG1AffineC16 +} + +// buckets: array of G1Affine queue operations (for the batch addition) +type qOpsG1Affine interface { + qG1AffineC10 | + qG1AffineC11 | + qG1AffineC12 | + qG1AffineC13 | + qG1AffineC14 | + qG1AffineC15 | + qG1AffineC16 +} + +// batch size 80 when c = 10 +type cG1AffineC10 [80]fp.Element +type pG1AffineC10 [80]G1Affine +type ppG1AffineC10 [80]*G1Affine +type qG1AffineC10 [80]batchOpG1Affine + +// batch size 150 when c = 11 +type cG1AffineC11 [150]fp.Element +type pG1AffineC11 [150]G1Affine +type ppG1AffineC11 [150]*G1Affine +type qG1AffineC11 [150]batchOpG1Affine + +// batch size 200 when c = 12 +type cG1AffineC12 [200]fp.Element +type pG1AffineC12 [200]G1Affine +type ppG1AffineC12 [200]*G1Affine +type qG1AffineC12 [200]batchOpG1Affine + +// batch size 350 when c = 13 +type cG1AffineC13 [350]fp.Element +type pG1AffineC13 [350]G1Affine +type ppG1AffineC13 [350]*G1Affine +type qG1AffineC13 [350]batchOpG1Affine + +// batch size 400 when c = 14 +type cG1AffineC14 [400]fp.Element +type pG1AffineC14 [400]G1Affine +type ppG1AffineC14 [400]*G1Affine +type qG1AffineC14 [400]batchOpG1Affine + +// batch size 500 when c = 15 +type cG1AffineC15 [500]fp.Element +type pG1AffineC15 [500]G1Affine +type ppG1AffineC15 [500]*G1Affine +type qG1AffineC15 [500]batchOpG1Affine + +// batch size 640 when c = 16 +type cG1AffineC16 [640]fp.Element +type pG1AffineC16 [640]G1Affine +type ppG1AffineC16 [640]*G1Affine +type qG1AffineC16 [640]batchOpG1Affine + +type batchOpG2Affine struct { + bucketID uint16 + point G2Affine +} + +// processChunkG2BatchAffine process a chunk of the scalars during the msm +// using affine coordinates for the buckets. To amortize the cost of the inverse in the affine addition +// we use a batch affine addition. +// +// this is derived from a PR by 0x0ece : https://github.com/ConsenSys/gnark-crypto/pull/249 +// See Section 5.3: ia.cr/2022/1396 +func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP pG2Affine, TPP ppG2Affine, TQ qOpsG2Affine, TC cG2Affine]( + chunk uint64, + chRes chan<- g2JacExtended, + c uint64, + points []G2Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + // the batch affine addition needs independent points; in other words, for a window of batchSize + // we want to hit independent bucketIDs when processing the digit. if there is a conflict (we're trying + // to add 2 different points to the same bucket), then we push the conflicted point to a queue. + // each time the batch is full, we execute it, and tentatively put the points (if not conflict) + // from the top of the queue into the next batch. + // if the queue is full, we "flush it"; we sequentially add the points to the buckets in + // g2JacExtended coordinates. + // The reasoning behind this is the following; batchSize is chosen such as, for a uniformly random + // input, the number of conflicts is going to be low, and the element added to the queue should be immediately + // processed in the next batch. If it's not the case, then our inputs are not random; and we fallback to + // non-batch-affine version. + + // note that we have 2 sets of buckets + // 1 in G2Affine used with the batch affine additions + // 1 in g2JacExtended used in case the queue of conflicting points + var buckets B + var bucketsJE BJE + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + bucketsJE[i].setInfinity() + } + + // setup for the batch affine; + var ( + bucketIds BS // bitSet to signify presence of a bucket in current batch + cptAdd int // count the number of bucket + point added to current batch + R TPP // bucket references + P TP // points to be added to R (buckets); it is beneficial to store them on the stack (ie copy) + queue TQ // queue of points that conflict the current batch + qID int // current position in queue + ) + + batchSize := len(P) + + isFull := func() bool { return cptAdd == batchSize } + + executeAndReset := func() { + batchAddG2Affine[TP, TPP, TC](&R, &P, cptAdd) + var tmp BS + bucketIds = tmp + cptAdd = 0 + } + + addFromQueue := func(op batchOpG2Affine) { + // @precondition: must ensures bucket is not "used" in current batch + // note that there is a bit of duplicate logic between add and addFromQueue + // the reason is that as of Go 1.19.3, if we pass a pointer to the queue item (see add signature) + // the compiler will put the queue on the heap. + BK := &buckets[op.bucketID] + + // handle special cases with inf or -P / P + if BK.IsInfinity() { + BK.Set(&op.point) + return + } + if BK.X.Equal(&op.point.X) { + if BK.Y.Equal(&op.point.Y) { + // P + P: doubling, which should be quite rare -- + // we use the other set of buckets + bucketsJE[op.bucketID].addMixed(&op.point) + return + } + BK.setInfinity() + return + } + + bucketIds[op.bucketID] = true + R[cptAdd] = BK + P[cptAdd] = op.point + cptAdd++ + } + + add := func(bucketID uint16, PP *G2Affine, isAdd bool) { + // @precondition: ensures bucket is not "used" in current batch + BK := &buckets[bucketID] + // handle special cases with inf or -P / P + if BK.IsInfinity() { + if isAdd { + BK.Set(PP) + } else { + BK.Neg(PP) + } + return + } + if BK.X.Equal(&PP.X) { + if BK.Y.Equal(&PP.Y) { + // P + P: doubling, which should be quite rare -- + if isAdd { + bucketsJE[bucketID].addMixed(PP) + } else { + BK.setInfinity() + } + return + } + if isAdd { + BK.setInfinity() + } else { + bucketsJE[bucketID].subMixed(PP) + } + return + } + + bucketIds[bucketID] = true + R[cptAdd] = BK + if isAdd { + P[cptAdd].Set(PP) + } else { + P[cptAdd].Neg(PP) + } + cptAdd++ + } + + flushQueue := func() { + for i := 0; i < qID; i++ { + bucketsJE[queue[i].bucketID].addMixed(&queue[i].point) + } + qID = 0 + } + + processTopQueue := func() { + for i := qID - 1; i >= 0; i-- { + if bucketIds[queue[i].bucketID] { + return + } + addFromQueue(queue[i]) + // len(queue) < batchSize so no need to check for full batch. + qID-- + } + } + + for i, digit := range digits { + + if digit == 0 || points[i].IsInfinity() { + continue + } + + bucketID := uint16((digit >> 1)) + isAdd := digit&1 == 0 + if isAdd { + // add + bucketID -= 1 + } + + if bucketIds[bucketID] { + // put it in queue + queue[qID].bucketID = bucketID + if isAdd { + queue[qID].point.Set(&points[i]) + } else { + queue[qID].point.Neg(&points[i]) + } + qID++ + + // queue is full, flush it. + if qID == len(queue)-1 { + flushQueue() + } + continue + } + + // we add the point to the batch. + add(bucketID, &points[i], isAdd) + if isFull() { + executeAndReset() + processTopQueue() + } + } + + // flush items in batch. + executeAndReset() + + // empty the queue + flushQueue() + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + var runningSum, total g2JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + runningSum.addMixed(&buckets[k]) + if !bucketsJE[k].IsZero() { + runningSum.add(&bucketsJE[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total + +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketG2AffineC10 [512]G2Affine +type bucketG2AffineC11 [1024]G2Affine +type bucketG2AffineC12 [2048]G2Affine +type bucketG2AffineC13 [4096]G2Affine +type bucketG2AffineC14 [8192]G2Affine +type bucketG2AffineC15 [16384]G2Affine +type bucketG2AffineC16 [32768]G2Affine + +// buckets: array of G2Affine points of size 1 << (c-1) +type ibG2Affine interface { + bucketG2AffineC10 | + bucketG2AffineC11 | + bucketG2AffineC12 | + bucketG2AffineC13 | + bucketG2AffineC14 | + bucketG2AffineC15 | + bucketG2AffineC16 +} + +// array of coordinates fptower.E2 +type cG2Affine interface { + cG2AffineC10 | + cG2AffineC11 | + cG2AffineC12 | + cG2AffineC13 | + cG2AffineC14 | + cG2AffineC15 | + cG2AffineC16 +} + +// buckets: array of G2Affine points (for the batch addition) +type pG2Affine interface { + pG2AffineC10 | + pG2AffineC11 | + pG2AffineC12 | + pG2AffineC13 | + pG2AffineC14 | + pG2AffineC15 | + pG2AffineC16 +} + +// buckets: array of *G2Affine points (for the batch addition) +type ppG2Affine interface { + ppG2AffineC10 | + ppG2AffineC11 | + ppG2AffineC12 | + ppG2AffineC13 | + ppG2AffineC14 | + ppG2AffineC15 | + ppG2AffineC16 +} + +// buckets: array of G2Affine queue operations (for the batch addition) +type qOpsG2Affine interface { + qG2AffineC10 | + qG2AffineC11 | + qG2AffineC12 | + qG2AffineC13 | + qG2AffineC14 | + qG2AffineC15 | + qG2AffineC16 +} + +// batch size 80 when c = 10 +type cG2AffineC10 [80]fptower.E2 +type pG2AffineC10 [80]G2Affine +type ppG2AffineC10 [80]*G2Affine +type qG2AffineC10 [80]batchOpG2Affine + +// batch size 150 when c = 11 +type cG2AffineC11 [150]fptower.E2 +type pG2AffineC11 [150]G2Affine +type ppG2AffineC11 [150]*G2Affine +type qG2AffineC11 [150]batchOpG2Affine + +// batch size 200 when c = 12 +type cG2AffineC12 [200]fptower.E2 +type pG2AffineC12 [200]G2Affine +type ppG2AffineC12 [200]*G2Affine +type qG2AffineC12 [200]batchOpG2Affine + +// batch size 350 when c = 13 +type cG2AffineC13 [350]fptower.E2 +type pG2AffineC13 [350]G2Affine +type ppG2AffineC13 [350]*G2Affine +type qG2AffineC13 [350]batchOpG2Affine + +// batch size 400 when c = 14 +type cG2AffineC14 [400]fptower.E2 +type pG2AffineC14 [400]G2Affine +type ppG2AffineC14 [400]*G2Affine +type qG2AffineC14 [400]batchOpG2Affine + +// batch size 500 when c = 15 +type cG2AffineC15 [500]fptower.E2 +type pG2AffineC15 [500]G2Affine +type ppG2AffineC15 [500]*G2Affine +type qG2AffineC15 [500]batchOpG2Affine + +// batch size 640 when c = 16 +type cG2AffineC16 [640]fptower.E2 +type pG2AffineC16 [640]G2Affine +type ppG2AffineC16 [640]*G2Affine +type qG2AffineC16 [640]batchOpG2Affine + +type bitSetC2 [2]bool +type bitSetC4 [8]bool +type bitSetC5 [16]bool +type bitSetC6 [32]bool +type bitSetC7 [64]bool +type bitSetC8 [128]bool +type bitSetC9 [256]bool +type bitSetC10 [512]bool +type bitSetC11 [1024]bool +type bitSetC12 [2048]bool +type bitSetC13 [4096]bool +type bitSetC14 [8192]bool +type bitSetC15 [16384]bool +type bitSetC16 [32768]bool + +type bitSet interface { + bitSetC2 | + bitSetC4 | + bitSetC5 | + bitSetC6 | + bitSetC7 | + bitSetC8 | + bitSetC9 | + bitSetC10 | + bitSetC11 | + bitSetC12 | + bitSetC13 | + bitSetC14 | + bitSetC15 | + bitSetC16 +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_jacobian.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_jacobian.go new file mode 100644 index 00000000000..0df516f5b9e --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp_jacobian.go @@ -0,0 +1,195 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12377 + +func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, + chRes chan<- g1JacExtended, + c uint64, + points []G1Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + var buckets B + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i, digit := range digits { + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + buckets[(digit>>1)-1].addMixed(&points[i]) + } else { + // sub + buckets[(digit >> 1)].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g1JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketg1JacExtendedC2 [2]g1JacExtended +type bucketg1JacExtendedC4 [8]g1JacExtended +type bucketg1JacExtendedC5 [16]g1JacExtended +type bucketg1JacExtendedC6 [32]g1JacExtended +type bucketg1JacExtendedC7 [64]g1JacExtended +type bucketg1JacExtendedC8 [128]g1JacExtended +type bucketg1JacExtendedC9 [256]g1JacExtended +type bucketg1JacExtendedC10 [512]g1JacExtended +type bucketg1JacExtendedC11 [1024]g1JacExtended +type bucketg1JacExtendedC12 [2048]g1JacExtended +type bucketg1JacExtendedC13 [4096]g1JacExtended +type bucketg1JacExtendedC14 [8192]g1JacExtended +type bucketg1JacExtendedC15 [16384]g1JacExtended +type bucketg1JacExtendedC16 [32768]g1JacExtended + +type ibg1JacExtended interface { + bucketg1JacExtendedC2 | + bucketg1JacExtendedC4 | + bucketg1JacExtendedC5 | + bucketg1JacExtendedC6 | + bucketg1JacExtendedC7 | + bucketg1JacExtendedC8 | + bucketg1JacExtendedC9 | + bucketg1JacExtendedC10 | + bucketg1JacExtendedC11 | + bucketg1JacExtendedC12 | + bucketg1JacExtendedC13 | + bucketg1JacExtendedC14 | + bucketg1JacExtendedC15 | + bucketg1JacExtendedC16 +} + +func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, + chRes chan<- g2JacExtended, + c uint64, + points []G2Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + var buckets B + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i, digit := range digits { + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + buckets[(digit>>1)-1].addMixed(&points[i]) + } else { + // sub + buckets[(digit >> 1)].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g2JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketg2JacExtendedC2 [2]g2JacExtended +type bucketg2JacExtendedC4 [8]g2JacExtended +type bucketg2JacExtendedC5 [16]g2JacExtended +type bucketg2JacExtendedC6 [32]g2JacExtended +type bucketg2JacExtendedC7 [64]g2JacExtended +type bucketg2JacExtendedC8 [128]g2JacExtended +type bucketg2JacExtendedC9 [256]g2JacExtended +type bucketg2JacExtendedC10 [512]g2JacExtended +type bucketg2JacExtendedC11 [1024]g2JacExtended +type bucketg2JacExtendedC12 [2048]g2JacExtended +type bucketg2JacExtendedC13 [4096]g2JacExtended +type bucketg2JacExtendedC14 [8192]g2JacExtended +type bucketg2JacExtendedC15 [16384]g2JacExtended +type bucketg2JacExtendedC16 [32768]g2JacExtended + +type ibg2JacExtended interface { + bucketg2JacExtendedC2 | + bucketg2JacExtendedC4 | + bucketg2JacExtendedC5 | + bucketg2JacExtendedC6 | + bucketg2JacExtendedC7 | + bucketg2JacExtendedC8 | + bucketg2JacExtendedC9 | + bucketg2JacExtendedC10 | + bucketg2JacExtendedC11 | + bucketg2JacExtendedC12 | + bucketg2JacExtendedC13 | + bucketg2JacExtendedC14 | + bucketg2JacExtendedC15 | + bucketg2JacExtendedC16 +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go new file mode 100644 index 00000000000..f670902e4b0 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go @@ -0,0 +1,343 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bls12377 + +import ( + "errors" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" +) + +// GT target group of the pairing +type GT = fptower.E12 + +type lineEvaluation struct { + r0 fptower.E2 + r1 fptower.E2 + r2 fptower.E2 +} + +// Pair calculates the reduced pairing for a set of points +// ∏ᵢ e(Pᵢ, Qᵢ). +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. +func Pair(P []G1Affine, Q []G2Affine) (GT, error) { + f, err := MillerLoop(P, Q) + if err != nil { + return GT{}, err + } + return FinalExponentiation(&f), nil +} + +// PairingCheck calculates the reduced pairing for a set of points and returns True if the result is One +// ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. +func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) { + f, err := Pair(P, Q) + if err != nil { + return false, err + } + var one GT + one.SetOne() + return f.Equal(&one), nil +} + +// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ +// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// where s is the cofactor 3 (Hayashida et al.) +func FinalExponentiation(z *GT, _z ...*GT) GT { + + var result GT + result.Set(z) + + for _, e := range _z { + result.Mul(&result, e) + } + + var t [3]GT + + // Easy part + // (p⁶-1)(p²+1) + t[0].Conjugate(&result) + result.Inverse(&result) + t[0].Mul(&t[0], &result) + result.FrobeniusSquare(&t[0]). + Mul(&result, &t[0]) + + var one GT + one.SetOne() + if result.Equal(&one) { + return result + } + + // Hard part (up to permutation) + // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya + // https://eprint.iacr.org/2020/875.pdf + t[0].CyclotomicSquare(&result) + t[1].Expt(&result) + t[2].InverseUnitary(&result) + t[1].Mul(&t[1], &t[2]) + t[2].Expt(&t[1]) + t[1].InverseUnitary(&t[1]) + t[1].Mul(&t[1], &t[2]) + t[2].Expt(&t[1]) + t[1].Frobenius(&t[1]) + t[1].Mul(&t[1], &t[2]) + result.Mul(&result, &t[0]) + t[0].Expt(&t[1]) + t[2].Expt(&t[0]) + t[0].FrobeniusSquare(&t[1]) + t[1].InverseUnitary(&t[1]) + t[1].Mul(&t[1], &t[2]) + t[1].Mul(&t[1], &t[0]) + result.Mul(&result, &t[1]) + + return result +} + +// MillerLoop computes the multi-Miller loop +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = ∏ᵢ { fᵢ_{x,Qᵢ}(Pᵢ) } +func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { + // check input size match + n := len(P) + if n == 0 || n != len(Q) { + return GT{}, errors.New("invalid inputs sizes") + } + + // filter infinity points + p := make([]G1Affine, 0, n) + q := make([]G2Affine, 0, n) + + for k := 0; k < n; k++ { + if P[k].IsInfinity() || Q[k].IsInfinity() { + continue + } + p = append(p, P[k]) + q = append(q, Q[k]) + } + + n = len(p) + + // projective points for Q + qProj := make([]g2Proj, n) + for k := 0; k < n; k++ { + qProj[k].FromAffine(&q[k]) + } + + var result GT + result.SetOne() + var l1, l2 lineEvaluation + var prodLines [5]E2 + + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + if n >= 1 { + // i = 62, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[62] = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] + qProj[0].doubleStep(&l1) + // line evaluation at P[0] (assign) + result.C0.B0.MulByElement(&l1.r0, &p[0].Y) + result.C1.B0.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.Set(&l1.r2) + } + + if n >= 2 { + // k = 1, separately to avoid MulBy034 (res × ℓ) + // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) + + // qProj[1] ← 2qProj[1] and l1 the tangent ℓ passing 2qProj[1] + qProj[1].doubleStep(&l1) + // line evaluation at P[1] + l1.r0.MulByElement(&l1.r0, &p[1].Y) + l1.r1.MulByElement(&l1.r1, &p[1].X) + // ℓ × res + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C1.B0, &result.C1.B1) + result.C0.B0 = prodLines[0] + result.C0.B1 = prodLines[1] + result.C0.B2 = prodLines[2] + result.C1.B0 = prodLines[3] + result.C1.B1 = prodLines[4] + } + + // k >= 2 + for k := 2; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] + qProj[k].doubleStep(&l1) + // line evaluation at P[k] + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + // ℓ × res + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) + } + + // i <= 61 + for i := len(loopCounter) - 3; i >= 1; i-- { + // mutualize the square among n Miller loops + // (∏ᵢfᵢ)² + result.Square(&result) + + for k := 0; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] + qProj[k].doubleStep(&l1) + // line evaluation at P[k] + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + + if loopCounter[i] == 0 { + // ℓ × res + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) + } else { + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] + qProj[k].addMixedStep(&l2, &q[k]) + // line evaluation at P[k] + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) + // ℓ × ℓ + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res + result.MulBy01234(&prodLines) + } + } + + } + + // i = 0, separately to avoid a point addition + // loopCounter[0] = 1 + result.Square(&result) + for k := 0; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] + qProj[k].doubleStep(&l1) + // line evaluation at P[k] + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + + // l2 the line passing qProj[k] and Q + qProj[k].lineCompute(&l2, &q[k]) + // line evaluation at P[k] + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) + // ℓ × ℓ + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res + result.MulBy01234(&prodLines) + } + + return result, nil +} + +// doubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2013/722.pdf (Section 4.3) +func (p *g2Proj) doubleStep(evaluations *lineEvaluation) { + + // get some Element from our pool + var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A.Mul(&p.x, &p.y) + A.Halve() + B.Square(&p.y) + C.Square(&p.z) + D.Double(&C). + Add(&D, &C) + E.MulBybTwistCurveCoeff(&D) + F.Double(&E). + Add(&F, &E) + G.Add(&B, &F) + G.Halve() + H.Add(&p.y, &p.z). + Square(&H) + t1.Add(&B, &C) + H.Sub(&H, &t1) + I.Sub(&E, &B) + J.Square(&p.x) + EE.Square(&E) + K.Double(&EE). + Add(&K, &EE) + + // X, Y, Z + p.x.Sub(&B, &F). + Mul(&p.x, &A) + p.y.Square(&G). + Sub(&p.y, &K) + p.z.Mul(&B, &H) + + // Line evaluation + evaluations.r0.Neg(&H) + evaluations.r1.Double(&J). + Add(&evaluations.r1, &J) + evaluations.r2.Set(&I) +} + +// addMixedStep point addition in Mixed Homogenous projective and Affine coordinates +// https://eprint.iacr.org/2013/722.pdf (Section 4.3) +func (p *g2Proj) addMixedStep(evaluations *lineEvaluation, a *G2Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1.Mul(&a.Y, &p.z) + O.Sub(&p.y, &Y2Z1) + X2Z1.Mul(&a.X, &p.z) + L.Sub(&p.x, &X2Z1) + C.Square(&O) + D.Square(&L) + E.Mul(&L, &D) + F.Mul(&p.z, &C) + G.Mul(&p.x, &D) + t0.Double(&G) + H.Add(&E, &F). + Sub(&H, &t0) + t1.Mul(&p.y, &E) + + // X, Y, Z + p.x.Mul(&L, &H) + p.y.Sub(&G, &H). + Mul(&p.y, &O). + Sub(&p.y, &t1) + p.z.Mul(&E, &p.z) + + t2.Mul(&L, &a.Y) + J.Mul(&a.X, &O). + Sub(&J, &t2) + + // Line evaluation + evaluations.r0.Set(&L) + evaluations.r1.Neg(&O) + evaluations.r2.Set(&J) +} + +// lineCompute computes the line through p in Homogenous projective coordinates +// and a in affine coordinates. It does not compute the resulting point p+a. +func (p *g2Proj) lineCompute(evaluations *lineEvaluation, a *G2Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, t2, J fptower.E2 + Y2Z1.Mul(&a.Y, &p.z) + O.Sub(&p.y, &Y2Z1) + X2Z1.Mul(&a.X, &p.z) + L.Sub(&p.x, &X2Z1) + t2.Mul(&L, &a.Y) + J.Mul(&a.X, &O). + Sub(&J, &t2) + + // Line evaluation + evaluations.r0.Set(&L) + evaluations.r1.Neg(&O) + evaluations.r2.Set(&J) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/bls12-381.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/bls12-381.go new file mode 100644 index 00000000000..86ab933a19f --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/bls12-381.go @@ -0,0 +1,157 @@ +// Package bls12381 efficient elliptic curve, pairing and hash to curve implementation for bls12-381. +// +// bls12-381: A Barreto--Lynn--Scott curve +// +// embedding degree k=12 +// seed x₀=-15132376222941642752 +// 𝔽r: r=52435875175126190479447740508185965837690552500527637822603658699938581184513 (x₀⁴-x₀²+1) +// 𝔽p: p=4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 ((x₀-1)² ⋅ r(x₀)/3+x₀) +// (E/𝔽p): Y²=X³+4 +// (Eₜ/𝔽p²): Y² = X³+4(u+1) (M-type twist) +// r ∣ #E(Fp) and r ∣ #Eₜ(𝔽p²) +// +// Extension fields tower: +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-1-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +// +// optimal Ate loop size: +// +// x₀ +// +// Security: estimated 126-bit level following [https://eprint.iacr.org/2019/885.pdf] +// (r is 255 bits and p¹² is 4569 bits) +// +// # Warning +// +// This code has been partially audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +package bls12381 + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" +) + +// ID bls381 ID +const ID = ecc.BLS12_381 + +// aCurveCoeff is the a coefficients of the curve Y²=X³+ax+b +var aCurveCoeff fp.Element +var bCurveCoeff fp.Element + +// twist +var twist fptower.E2 + +// bTwistCurveCoeff b coeff of the twist (defined over 𝔽p²) curve +var bTwistCurveCoeff fptower.E2 + +// generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) +var g1Gen G1Jac +var g2Gen G2Jac + +var g1GenAff G1Affine +var g2GenAff G2Affine + +// point at infinity +var g1Infinity G1Jac +var g2Infinity G2Jac + +// optimal Ate loop counter +var loopCounter [64]int8 + +// Parameters useful for the GLV scalar multiplication. The third roots define the +// endomorphisms ϕ₁ and ϕ₂ for and . lambda is such that lies above +// in the ring Z[ϕ]. More concretely it's the associated eigenvalue +// of ϕ₁ (resp ϕ₂) restricted to (resp ) +// see https://www.cosic.esat.kuleuven.be/nessie/reports/phase2/GLV.pdf +var thirdRootOneG1 fp.Element +var thirdRootOneG2 fp.Element +var lambdaGLV big.Int + +// glvBasis stores R-linearly independent vectors (a,b), (c,d) +// in ker((u,v) → u+vλ[r]), and their determinant +var glvBasis ecc.Lattice + +// ψ o π o ψ^{-1}, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² +var endo struct { + u fptower.E2 + v fptower.E2 +} + +// seed x₀ of the curve +var xGen big.Int + +// 𝔽p² +type E2 = fptower.E2 + +// 𝔽p⁶ +type E6 = fptower.E6 + +// 𝔽p¹² +type E12 = fptower.E12 + +func init() { + aCurveCoeff.SetUint64(0) + bCurveCoeff.SetUint64(4) + // M-twist + twist.A0.SetUint64(1) + twist.A1.SetUint64(1) + bTwistCurveCoeff.MulByElement(&twist, &bCurveCoeff) + + g1Gen.X.SetString("3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507") + g1Gen.Y.SetString("1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569") + g1Gen.Z.SetOne() + + g2Gen.X.SetString("352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160", + "3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758") + g2Gen.Y.SetString("1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905", + "927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582") + g2Gen.Z.SetString("1", + "0") + + g1GenAff.FromJacobian(&g1Gen) + g2GenAff.FromJacobian(&g2Gen) + + // (X,Y,Z) = (1,1,0) + g1Infinity.X.SetOne() + g1Infinity.Y.SetOne() + g2Infinity.X.SetOne() + g2Infinity.Y.SetOne() + + thirdRootOneG1.SetString("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436") + thirdRootOneG2.Square(&thirdRootOneG1) + lambdaGLV.SetString("228988810152649578064853576960394133503", 10) //(x₀²-1) + _r := fr.Modulus() + ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + + endo.u.A0.SetString("0") + endo.u.A1.SetString("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") + endo.v.A0.SetString("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530") + endo.v.A1.SetString("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257") + + // binary decomposition of -x₀ little endian + loopCounter = [64]int8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1} + + // -x₀ + xGen.SetString("15132376222941642752", 10) + +} + +// Generators return the generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) +func Generators() (g1Jac G1Jac, g2Jac G2Jac, g1Aff G1Affine, g2Aff G2Affine) { + g1Aff = g1GenAff + g2Aff = g2GenAff + g1Jac = g1Gen + g2Jac = g2Gen + return +} + +// CurveCoefficients returns the a, b coefficients of the curve equation. +func CurveCoefficients() (a, b fp.Element) { + return aCurveCoeff, bCurveCoeff +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/arith.go new file mode 100644 index 00000000000..6f281563b3d --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/arith.go @@ -0,0 +1,73 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "math/bits" +) + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} +func max(a int, b int) int { + if a > b { + return a + } + return b +} + +func min(a int, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/asm.go similarity index 73% rename from vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/fuzz.go rename to vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/asm.go index 41b557cf3f7..0481989ec6a 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/fuzz.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/asm.go @@ -1,5 +1,5 @@ -//go:build gofuzz -// +build gofuzz +//go:build !noadx +// +build !noadx // Copyright 2020 ConsenSys Software Inc. // @@ -17,18 +17,11 @@ // Code generated by consensys/gnark-crypto DO NOT EDIT -package mimc +package fp -const ( - fuzzInteresting = 1 - fuzzNormal = 0 - fuzzDiscard = -1 -) +import "golang.org/x/sys/cpu" -func Fuzz(data []byte) int { - var s []byte - h := NewMiMC(string(data)) - h.Write(data) - h.Sum(s) - return fuzzNormal -} +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/asm_noadx.go new file mode 100644 index 00000000000..92f8cc0f424 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/asm_noadx.go @@ -0,0 +1,28 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var ( + supportAdx = false + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/doc.go new file mode 100644 index 00000000000..bf5b82c113b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/doc.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package fp contains field arithmetic operations for modulus = 0x1a0111...ffaaab. +// +// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x for the modular multiplication on amd64, see also https://hackmd.io/@gnark/modular_multiplication) +// +// The modulus is hardcoded in all the operations. +// +// Field elements are represented as an array, and assumed to be in Montgomery form in all methods: +// +// type Element [6]uint64 +// +// # Usage +// +// Example API signature: +// +// // Mul z = x * y (mod q) +// func (z *Element) Mul(x, y *Element) *Element +// +// and can be used like so: +// +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus q = +// +// q[base10] = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 +// q[base16] = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +package fp diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element.go new file mode 100644 index 00000000000..f5c2df0c28a --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element.go @@ -0,0 +1,1794 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "crypto/rand" + "encoding/binary" + "errors" + "io" + "math/big" + "math/bits" + "reflect" + "strconv" + "strings" + + "github.com/bits-and-blooms/bitset" + "github.com/consensys/gnark-crypto/field/hash" + "github.com/consensys/gnark-crypto/field/pool" +) + +// Element represents a field element stored on 6 words (uint64) +// +// Element are assumed to be in Montgomery form in all methods. +// +// Modulus q = +// +// q[base10] = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 +// q[base16] = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +type Element [6]uint64 + +const ( + Limbs = 6 // number of 64 bits words needed to represent a Element + Bits = 381 // number of bits needed to represent a Element + Bytes = 48 // number of bytes needed to represent a Element +) + +// Field modulus q +const ( + q0 uint64 = 13402431016077863595 + q1 uint64 = 2210141511517208575 + q2 uint64 = 7435674573564081700 + q3 uint64 = 7239337960414712511 + q4 uint64 = 5412103778470702295 + q5 uint64 = 1873798617647539866 +) + +var qElement = Element{ + q0, + q1, + q2, + q3, + q4, + q5, +} + +var _modulus big.Int // q stored as big.Int + +// Modulus returns q as a big.Int +// +// q[base10] = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 +// q[base16] = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab +func Modulus() *big.Int { + return new(big.Int).Set(&_modulus) +} + +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 9940570264628428797 + +func init() { + _modulus.SetString("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16) +} + +// NewElement returns a new Element from a uint64 value +// +// it is equivalent to +// +// var v Element +// v.SetUint64(...) +func NewElement(v uint64) Element { + z := Element{v} + z.Mul(&z, &rSquare) + return z +} + +// SetUint64 sets z to v and returns z +func (z *Element) SetUint64(v uint64) *Element { + // sets z LSB to v (non-Montgomery form) and convert z to Montgomery form + *z = Element{v} + return z.Mul(z, &rSquare) // z.toMont() +} + +// SetInt64 sets z to v and returns z +func (z *Element) SetInt64(v int64) *Element { + + // absolute value of v + m := v >> 63 + z.SetUint64(uint64((v ^ m) - m)) + + if m != 0 { + // v is negative + z.Neg(z) + } + + return z +} + +// Set z = x and returns z +func (z *Element) Set(x *Element) *Element { + z[0] = x[0] + z[1] = x[1] + z[2] = x[2] + z[3] = x[3] + z[4] = x[4] + z[5] = x[5] + return z +} + +// SetInterface converts provided interface into Element +// returns an error if provided type is not supported +// supported types: +// +// Element +// *Element +// uint64 +// int +// string (see SetString for valid formats) +// *big.Int +// big.Int +// []byte +func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + if i1 == nil { + return nil, errors.New("can't set fp.Element with ") + } + + switch c1 := i1.(type) { + case Element: + return z.Set(&c1), nil + case *Element: + if c1 == nil { + return nil, errors.New("can't set fp.Element with ") + } + return z.Set(c1), nil + case uint8: + return z.SetUint64(uint64(c1)), nil + case uint16: + return z.SetUint64(uint64(c1)), nil + case uint32: + return z.SetUint64(uint64(c1)), nil + case uint: + return z.SetUint64(uint64(c1)), nil + case uint64: + return z.SetUint64(c1), nil + case int8: + return z.SetInt64(int64(c1)), nil + case int16: + return z.SetInt64(int64(c1)), nil + case int32: + return z.SetInt64(int64(c1)), nil + case int64: + return z.SetInt64(c1), nil + case int: + return z.SetInt64(int64(c1)), nil + case string: + return z.SetString(c1) + case *big.Int: + if c1 == nil { + return nil, errors.New("can't set fp.Element with ") + } + return z.SetBigInt(c1), nil + case big.Int: + return z.SetBigInt(&c1), nil + case []byte: + return z.SetBytes(c1), nil + default: + return nil, errors.New("can't set fp.Element from type " + reflect.TypeOf(i1).String()) + } +} + +// SetZero z = 0 +func (z *Element) SetZero() *Element { + z[0] = 0 + z[1] = 0 + z[2] = 0 + z[3] = 0 + z[4] = 0 + z[5] = 0 + return z +} + +// SetOne z = 1 (in Montgomery form) +func (z *Element) SetOne() *Element { + z[0] = 8505329371266088957 + z[1] = 17002214543764226050 + z[2] = 6865905132761471162 + z[3] = 8632934651105793861 + z[4] = 6631298214892334189 + z[5] = 1582556514881692819 + return z +} + +// Div z = x*y⁻¹ (mod q) +func (z *Element) Div(x, y *Element) *Element { + var yInv Element + yInv.Inverse(y) + z.Mul(x, &yInv) + return z +} + +// Equal returns z == x; constant-time +func (z *Element) Equal(x *Element) bool { + return z.NotEqual(x) == 0 +} + +// NotEqual returns 0 if and only if z == x; constant-time +func (z *Element) NotEqual(x *Element) uint64 { + return (z[5] ^ x[5]) | (z[4] ^ x[4]) | (z[3] ^ x[3]) | (z[2] ^ x[2]) | (z[1] ^ x[1]) | (z[0] ^ x[0]) +} + +// IsZero returns z == 0 +func (z *Element) IsZero() bool { + return (z[5] | z[4] | z[3] | z[2] | z[1] | z[0]) == 0 +} + +// IsOne returns z == 1 +func (z *Element) IsOne() bool { + return ((z[5] ^ 1582556514881692819) | (z[4] ^ 6631298214892334189) | (z[3] ^ 8632934651105793861) | (z[2] ^ 6865905132761471162) | (z[1] ^ 17002214543764226050) | (z[0] ^ 8505329371266088957)) == 0 +} + +// IsUint64 reports whether z can be represented as an uint64. +func (z *Element) IsUint64() bool { + zz := *z + zz.fromMont() + return zz.FitsOnOneWord() +} + +// Uint64 returns the uint64 representation of x. If x cannot be represented in a uint64, the result is undefined. +func (z *Element) Uint64() uint64 { + return z.Bits()[0] +} + +// FitsOnOneWord reports whether z words (except the least significant word) are 0 +// +// It is the responsibility of the caller to convert from Montgomery to Regular form if needed. +func (z *Element) FitsOnOneWord() bool { + return (z[5] | z[4] | z[3] | z[2] | z[1]) == 0 +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *Element) Cmp(x *Element) int { + _z := z.Bits() + _x := x.Bits() + if _z[5] > _x[5] { + return 1 + } else if _z[5] < _x[5] { + return -1 + } + if _z[4] > _x[4] { + return 1 + } else if _z[4] < _x[4] { + return -1 + } + if _z[3] > _x[3] { + return 1 + } else if _z[3] < _x[3] { + return -1 + } + if _z[2] > _x[2] { + return 1 + } else if _z[2] < _x[2] { + return -1 + } + if _z[1] > _x[1] { + return 1 + } else if _z[1] < _x[1] { + return -1 + } + if _z[0] > _x[0] { + return 1 + } else if _z[0] < _x[0] { + return -1 + } + return 0 +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *Element) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + // we check if the element is larger than (q-1) / 2 + // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 + + _z := z.Bits() + + var b uint64 + _, b = bits.Sub64(_z[0], 15924587544893707606, 0) + _, b = bits.Sub64(_z[1], 1105070755758604287, b) + _, b = bits.Sub64(_z[2], 12941209323636816658, b) + _, b = bits.Sub64(_z[3], 12843041017062132063, b) + _, b = bits.Sub64(_z[4], 2706051889235351147, b) + _, b = bits.Sub64(_z[5], 936899308823769933, b) + + return b == 0 +} + +// SetRandom sets z to a uniform random value in [0, q). +// +// This might error only if reading from crypto/rand.Reader errors, +// in which case, value of z is undefined. +func (z *Element) SetRandom() (*Element, error) { + // this code is generated for all modulus + // and derived from go/src/crypto/rand/util.go + + // l is number of limbs * 8; the number of bytes needed to reconstruct 6 uint64 + const l = 48 + + // bitLen is the maximum bit length needed to encode a value < q. + const bitLen = 381 + + // k is the maximum byte length needed to encode a value < q. + const k = (bitLen + 7) / 8 + + // b is the number of bits in the most significant byte of q-1. + b := uint(bitLen % 8) + if b == 0 { + b = 8 + } + + var bytes [l]byte + + for { + // note that bytes[k:l] is always 0 + if _, err := io.ReadFull(rand.Reader, bytes[:k]); err != nil { + return nil, err + } + + // Clear unused bits in in the most significant byte to increase probability + // that the candidate is < q. + bytes[k-1] &= uint8(int(1<> 1 + z[0] = z[0]>>1 | z[1]<<63 + z[1] = z[1]>>1 | z[2]<<63 + z[2] = z[2]>>1 | z[3]<<63 + z[3] = z[3]>>1 | z[4]<<63 + z[4] = z[4]>>1 | z[5]<<63 + z[5] >>= 1 + +} + +// fromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func (z *Element) fromMont() *Element { + fromMont(z) + return z +} + +// Add z = x + y (mod q) +func (z *Element) Add(x, y *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], carry = bits.Add64(x[3], y[3], carry) + z[4], carry = bits.Add64(x[4], y[4], carry) + z[5], _ = bits.Add64(x[5], y[5], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} + +// Double z = x + x (mod q), aka Lsh 1 +func (z *Element) Double(x *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], carry = bits.Add64(x[3], x[3], carry) + z[4], carry = bits.Add64(x[4], x[4], carry) + z[5], _ = bits.Add64(x[5], x[5], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} + +// Sub z = x - y (mod q) +func (z *Element) Sub(x, y *Element) *Element { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + z[4], b = bits.Sub64(x[4], y[4], b) + z[5], b = bits.Sub64(x[5], y[5], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], q0, 0) + z[1], c = bits.Add64(z[1], q1, c) + z[2], c = bits.Add64(z[2], q2, c) + z[3], c = bits.Add64(z[3], q3, c) + z[4], c = bits.Add64(z[4], q4, c) + z[5], _ = bits.Add64(z[5], q5, c) + } + return z +} + +// Neg z = q - x +func (z *Element) Neg(x *Element) *Element { + if x.IsZero() { + z.SetZero() + return z + } + var borrow uint64 + z[0], borrow = bits.Sub64(q0, x[0], 0) + z[1], borrow = bits.Sub64(q1, x[1], borrow) + z[2], borrow = bits.Sub64(q2, x[2], borrow) + z[3], borrow = bits.Sub64(q3, x[3], borrow) + z[4], borrow = bits.Sub64(q4, x[4], borrow) + z[5], _ = bits.Sub64(q5, x[5], borrow) + return z +} + +// Select is a constant-time conditional move. +// If c=0, z = x0. Else z = x1 +func (z *Element) Select(c int, x0 *Element, x1 *Element) *Element { + cC := uint64((int64(c) | -int64(c)) >> 63) // "canonicized" into: 0 if c=0, -1 otherwise + z[0] = x0[0] ^ cC&(x0[0]^x1[0]) + z[1] = x0[1] ^ cC&(x0[1]^x1[1]) + z[2] = x0[2] ^ cC&(x0[2]^x1[2]) + z[3] = x0[3] ^ cC&(x0[3]^x1[3]) + z[4] = x0[4] ^ cC&(x0[4]^x1[4]) + z[5] = x0[5] ^ cC&(x0[5]^x1[5]) + return z +} + +// _mulGeneric is unoptimized textbook CIOS +// it is a fallback solution on x86 when ADX instruction set is not available +// and is used for testing purposes. +func _mulGeneric(z, x, y *Element) { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + + var t [7]uint64 + var D uint64 + var m, C uint64 + // ----------------------------------- + // First loop + + C, t[0] = bits.Mul64(y[0], x[0]) + C, t[1] = madd1(y[0], x[1], C) + C, t[2] = madd1(y[0], x[2], C) + C, t[3] = madd1(y[0], x[3], C) + C, t[4] = madd1(y[0], x[4], C) + C, t[5] = madd1(y[0], x[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[1], x[0], t[0]) + C, t[1] = madd2(y[1], x[1], t[1], C) + C, t[2] = madd2(y[1], x[2], t[2], C) + C, t[3] = madd2(y[1], x[3], t[3], C) + C, t[4] = madd2(y[1], x[4], t[4], C) + C, t[5] = madd2(y[1], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[2], x[0], t[0]) + C, t[1] = madd2(y[2], x[1], t[1], C) + C, t[2] = madd2(y[2], x[2], t[2], C) + C, t[3] = madd2(y[2], x[3], t[3], C) + C, t[4] = madd2(y[2], x[4], t[4], C) + C, t[5] = madd2(y[2], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[3], x[0], t[0]) + C, t[1] = madd2(y[3], x[1], t[1], C) + C, t[2] = madd2(y[3], x[2], t[2], C) + C, t[3] = madd2(y[3], x[3], t[3], C) + C, t[4] = madd2(y[3], x[4], t[4], C) + C, t[5] = madd2(y[3], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[4], x[0], t[0]) + C, t[1] = madd2(y[4], x[1], t[1], C) + C, t[2] = madd2(y[4], x[2], t[2], C) + C, t[3] = madd2(y[4], x[3], t[3], C) + C, t[4] = madd2(y[4], x[4], t[4], C) + C, t[5] = madd2(y[4], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[5], x[0], t[0]) + C, t[1] = madd2(y[5], x[1], t[1], C) + C, t[2] = madd2(y[5], x[2], t[2], C) + C, t[3] = madd2(y[5], x[3], t[3], C) + C, t[4] = madd2(y[5], x[4], t[4], C) + C, t[5] = madd2(y[5], x[5], t[5], C) + + t[6], D = bits.Add64(t[6], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + C, t[3] = madd2(m, q4, t[4], C) + C, t[4] = madd2(m, q5, t[5], C) + + t[5], C = bits.Add64(t[6], C, 0) + t[6], _ = bits.Add64(0, D, C) + + if t[6] != 0 { + // we need to reduce, we have a result on 7 words + var b uint64 + z[0], b = bits.Sub64(t[0], q0, 0) + z[1], b = bits.Sub64(t[1], q1, b) + z[2], b = bits.Sub64(t[2], q2, b) + z[3], b = bits.Sub64(t[3], q3, b) + z[4], b = bits.Sub64(t[4], q4, b) + z[5], _ = bits.Sub64(t[5], q5, b) + return + } + + // copy t into z + z[0] = t[0] + z[1] = t[1] + z[2] = t[2] + z[3] = t[3] + z[4] = t[4] + z[5] = t[5] + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } +} + +func _fromMontGeneric(z *Element) { + // the following lines implement z = z * 1 + // with a modified CIOS montgomery multiplication + // see Mul for algorithm documentation + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + C, z[3] = madd2(m, q4, z[4], C) + C, z[4] = madd2(m, q5, z[5], C) + z[5] = C + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } +} + +func _reduceGeneric(z *Element) { + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } +} + +// BatchInvert returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +func BatchInvert(a []Element) []Element { + res := make([]Element, len(a)) + if len(a) == 0 { + return res + } + + zeroes := bitset.New(uint(len(a))) + accumulator := One() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes.Set(uint(i)) + continue + } + res[i] = accumulator + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes.Test(uint(i)) { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func _butterflyGeneric(a, b *Element) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// BitLen returns the minimum number of bits needed to represent z +// returns 0 if z == 0 +func (z *Element) BitLen() int { + if z[5] != 0 { + return 320 + bits.Len64(z[5]) + } + if z[4] != 0 { + return 256 + bits.Len64(z[4]) + } + if z[3] != 0 { + return 192 + bits.Len64(z[3]) + } + if z[2] != 0 { + return 128 + bits.Len64(z[2]) + } + if z[1] != 0 { + return 64 + bits.Len64(z[1]) + } + return bits.Len64(z[0]) +} + +// Hash msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func Hash(msg, dst []byte, count int) ([]Element, error) { + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + const Bytes = 1 + (Bits-1)/8 + const L = 16 + Bytes + + lenInBytes := count * L + pseudoRandomBytes, err := hash.ExpandMsgXmd(msg, dst, lenInBytes) + if err != nil { + return nil, err + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + res := make([]Element, count) + for i := 0; i < count; i++ { + vv.SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + res[i].SetBigInt(vv) + } + + // release object into pool + pool.BigInt.Put(vv) + + return res, nil +} + +// Exp z = xᵏ (mod q) +func (z *Element) Exp(x Element, k *big.Int) *Element { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q) == (x⁻¹)ᵏ (mod q) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = pool.BigInt.Get() + defer pool.BigInt.Put(e) + e.Neg(k) + } + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// rSquare where r is the Montgommery constant +// see section 2.3.2 of Tolga Acar's thesis +// https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf +var rSquare = Element{ + 17644856173732828998, + 754043588434789617, + 10224657059481499349, + 7488229067341005760, + 11130996698012816685, + 1267921511277847466, +} + +// toMont converts z to Montgomery form +// sets and returns z = z * r² +func (z *Element) toMont() *Element { + return z.Mul(z, &rSquare) +} + +// String returns the decimal representation of z as generated by +// z.Text(10). +func (z *Element) String() string { + return z.Text(10) +} + +// toBigInt returns z as a big.Int in Montgomery form +func (z *Element) toBigInt(res *big.Int) *big.Int { + var b [Bytes]byte + binary.BigEndian.PutUint64(b[40:48], z[0]) + binary.BigEndian.PutUint64(b[32:40], z[1]) + binary.BigEndian.PutUint64(b[24:32], z[2]) + binary.BigEndian.PutUint64(b[16:24], z[3]) + binary.BigEndian.PutUint64(b[8:16], z[4]) + binary.BigEndian.PutUint64(b[0:8], z[5]) + + return res.SetBytes(b[:]) +} + +// Text returns the string representation of z in the given base. +// Base must be between 2 and 36, inclusive. The result uses the +// lower-case letters 'a' to 'z' for digit values 10 to 35. +// No prefix (such as "0x") is added to the string. If z is a nil +// pointer it returns "". +// If base == 10 and -z fits in a uint16 prefix "-" is added to the string. +func (z *Element) Text(base int) string { + if base < 2 || base > 36 { + panic("invalid base") + } + if z == nil { + return "" + } + + const maxUint16 = 65535 + if base == 10 { + var zzNeg Element + zzNeg.Neg(z) + zzNeg.fromMont() + if zzNeg.FitsOnOneWord() && zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { + return "-" + strconv.FormatUint(zzNeg[0], base) + } + } + zz := *z + zz.fromMont() + if zz.FitsOnOneWord() { + return strconv.FormatUint(zz[0], base) + } + vv := pool.BigInt.Get() + r := zz.toBigInt(vv).Text(base) + pool.BigInt.Put(vv) + return r +} + +// BigInt sets and return z as a *big.Int +func (z *Element) BigInt(res *big.Int) *big.Int { + _z := *z + _z.fromMont() + return _z.toBigInt(res) +} + +// ToBigIntRegular returns z as a big.Int in regular form +// +// Deprecated: use BigInt(*big.Int) instead +func (z Element) ToBigIntRegular(res *big.Int) *big.Int { + z.fromMont() + return z.toBigInt(res) +} + +// Bits provides access to z by returning its value as a little-endian [6]uint64 array. +// Bits is intended to support implementation of missing low-level Element +// functionality outside this package; it should be avoided otherwise. +func (z *Element) Bits() [6]uint64 { + _z := *z + fromMont(&_z) + return _z +} + +// Bytes returns the value of z as a big-endian byte array +func (z *Element) Bytes() (res [Bytes]byte) { + BigEndian.PutElement(&res, *z) + return +} + +// Marshal returns the value of z as a big-endian byte slice +func (z *Element) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// Unmarshal is an alias for SetBytes, it sets z to the value of e. +func (z *Element) Unmarshal(e []byte) { + z.SetBytes(e) +} + +// SetBytes interprets e as the bytes of a big-endian unsigned integer, +// sets z to that value, and returns z. +func (z *Element) SetBytes(e []byte) *Element { + if len(e) == Bytes { + // fast path + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err == nil { + *z = v + return z + } + } + + // slow path. + // get a big int from our pool + vv := pool.BigInt.Get() + vv.SetBytes(e) + + // set big int + z.SetBigInt(vv) + + // put temporary object back in pool + pool.BigInt.Put(vv) + + return z +} + +// SetBytesCanonical interprets e as the bytes of a big-endian 48-byte integer. +// If e is not a 48-byte slice or encodes a value higher than q, +// SetBytesCanonical returns an error. +func (z *Element) SetBytesCanonical(e []byte) error { + if len(e) != Bytes { + return errors.New("invalid fp.Element encoding") + } + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err != nil { + return err + } + *z = v + return nil +} + +// SetBigInt sets z to v and returns z +func (z *Element) SetBigInt(v *big.Int) *Element { + z.SetZero() + + var zero big.Int + + // fast path + c := v.Cmp(&_modulus) + if c == 0 { + // v == 0 + return z + } else if c != 1 && v.Cmp(&zero) != -1 { + // 0 < v < q + return z.setBigInt(v) + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + // copy input + modular reduction + vv.Mod(v, &_modulus) + + // set big int byte value + z.setBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return z +} + +// setBigInt assumes 0 ⩽ v < q +func (z *Element) setBigInt(v *big.Int) *Element { + vBits := v.Bits() + + if bits.UintSize == 64 { + for i := 0; i < len(vBits); i++ { + z[i] = uint64(vBits[i]) + } + } else { + for i := 0; i < len(vBits); i++ { + if i%2 == 0 { + z[i/2] = uint64(vBits[i]) + } else { + z[i/2] |= uint64(vBits[i]) << 32 + } + } + } + + return z.toMont() +} + +// SetString creates a big.Int with number and calls SetBigInt on z +// +// The number prefix determines the actual base: A prefix of +// ”0b” or ”0B” selects base 2, ”0”, ”0o” or ”0O” selects base 8, +// and ”0x” or ”0X” selects base 16. Otherwise, the selected base is 10 +// and no prefix is accepted. +// +// For base 16, lower and upper case letters are considered the same: +// The letters 'a' to 'f' and 'A' to 'F' represent digit values 10 to 15. +// +// An underscore character ”_” may appear between a base +// prefix and an adjacent digit, and between successive digits; such +// underscores do not change the value of the number. +// Incorrect placement of underscores is reported as a panic if there +// are no other errors. +// +// If the number is invalid this method leaves z unchanged and returns nil, error. +func (z *Element) SetString(number string) (*Element, error) { + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(number, 0); !ok { + return nil, errors.New("Element.SetString failed -> can't parse number into a big.Int " + number) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + + return z, nil +} + +// MarshalJSON returns json encoding of z (z.Text(10)) +// If z == nil, returns null +func (z *Element) MarshalJSON() ([]byte, error) { + if z == nil { + return []byte("null"), nil + } + const maxSafeBound = 15 // we encode it as number if it's small + s := z.Text(10) + if len(s) <= maxSafeBound { + return []byte(s), nil + } + var sbb strings.Builder + sbb.WriteByte('"') + sbb.WriteString(s) + sbb.WriteByte('"') + return []byte(sbb.String()), nil +} + +// UnmarshalJSON accepts numbers and strings as input +// See Element.SetString for valid prefixes (0x, 0b, ...) +func (z *Element) UnmarshalJSON(data []byte) error { + s := string(data) + if len(s) > Bits*3 { + return errors.New("value too large (max = Element.Bits * 3)") + } + + // we accept numbers and strings, remove leading and trailing quotes if any + if len(s) > 0 && s[0] == '"' { + s = s[1:] + } + if len(s) > 0 && s[len(s)-1] == '"' { + s = s[:len(s)-1] + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(s, 0); !ok { + return errors.New("can't parse into a big.Int: " + s) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return nil +} + +// A ByteOrder specifies how to convert byte slices into a Element +type ByteOrder interface { + Element(*[Bytes]byte) (Element, error) + PutElement(*[Bytes]byte, Element) + String() string +} + +// BigEndian is the big-endian implementation of ByteOrder and AppendByteOrder. +var BigEndian bigEndian + +type bigEndian struct{} + +// Element interpret b is a big-endian 48-byte slice. +// If b encodes a value higher than q, Element returns error. +func (bigEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.BigEndian.Uint64((*b)[40:48]) + z[1] = binary.BigEndian.Uint64((*b)[32:40]) + z[2] = binary.BigEndian.Uint64((*b)[24:32]) + z[3] = binary.BigEndian.Uint64((*b)[16:24]) + z[4] = binary.BigEndian.Uint64((*b)[8:16]) + z[5] = binary.BigEndian.Uint64((*b)[0:8]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fp.Element encoding") + } + + z.toMont() + return z, nil +} + +func (bigEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.BigEndian.PutUint64((*b)[40:48], e[0]) + binary.BigEndian.PutUint64((*b)[32:40], e[1]) + binary.BigEndian.PutUint64((*b)[24:32], e[2]) + binary.BigEndian.PutUint64((*b)[16:24], e[3]) + binary.BigEndian.PutUint64((*b)[8:16], e[4]) + binary.BigEndian.PutUint64((*b)[0:8], e[5]) +} + +func (bigEndian) String() string { return "BigEndian" } + +// LittleEndian is the little-endian implementation of ByteOrder and AppendByteOrder. +var LittleEndian littleEndian + +type littleEndian struct{} + +func (littleEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.LittleEndian.Uint64((*b)[0:8]) + z[1] = binary.LittleEndian.Uint64((*b)[8:16]) + z[2] = binary.LittleEndian.Uint64((*b)[16:24]) + z[3] = binary.LittleEndian.Uint64((*b)[24:32]) + z[4] = binary.LittleEndian.Uint64((*b)[32:40]) + z[5] = binary.LittleEndian.Uint64((*b)[40:48]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fp.Element encoding") + } + + z.toMont() + return z, nil +} + +func (littleEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.LittleEndian.PutUint64((*b)[0:8], e[0]) + binary.LittleEndian.PutUint64((*b)[8:16], e[1]) + binary.LittleEndian.PutUint64((*b)[16:24], e[2]) + binary.LittleEndian.PutUint64((*b)[24:32], e[3]) + binary.LittleEndian.PutUint64((*b)[32:40], e[4]) + binary.LittleEndian.PutUint64((*b)[40:48], e[5]) +} + +func (littleEndian) String() string { return "LittleEndian" } + +// Legendre returns the Legendre symbol of z (either +1, -1, or 0.) +func (z *Element) Legendre() int { + var l Element + // z^((q-1)/2) + l.expByLegendreExp(*z) + + if l.IsZero() { + return 0 + } + + // if l == 1 + if l.IsOne() { + return 1 + } + return -1 +} + +// Sqrt z = √x (mod q) +// if the square root doesn't exist (x is not a square mod q) +// Sqrt leaves z unchanged and returns nil +func (z *Element) Sqrt(x *Element) *Element { + // q ≡ 3 (mod 4) + // using z ≡ ± x^((p+1)/4) (mod q) + var y, square Element + y.expBySqrtExp(*x) + // as we didn't compute the legendre symbol, ensure we found y such that y * y = x + square.Square(&y) + if square.Equal(x) { + return z.Set(&y) + } + return nil +} + +const ( + k = 32 // word size / 2 + signBitSelector = uint64(1) << 63 + approxLowBitsN = k - 1 + approxHighBitsN = k + 1 +) + +const ( + inversionCorrectionFactorWord0 = 8737414717120368535 + inversionCorrectionFactorWord1 = 10094300570241649429 + inversionCorrectionFactorWord2 = 6339946188669102923 + inversionCorrectionFactorWord3 = 10492640117780001228 + inversionCorrectionFactorWord4 = 12201317704601795701 + inversionCorrectionFactorWord5 = 1158882751927031822 + invIterationsN = 26 +) + +// Inverse z = x⁻¹ (mod q) +// +// if x == 0, sets and returns z = x +func (z *Element) Inverse(x *Element) *Element { + // Implements "Optimized Binary GCD for Modular Inversion" + // https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf + + a := *x + b := Element{ + q0, + q1, + q2, + q3, + q4, + q5, + } // b := q + + u := Element{1} + + // Update factors: we get [u; v] ← [f₀ g₀; f₁ g₁] [u; v] + // cᵢ = fᵢ + 2³¹ - 1 + 2³² * (gᵢ + 2³¹ - 1) + var c0, c1 int64 + + // Saved update factors to reduce the number of field multiplications + var pf0, pf1, pg0, pg1 int64 + + var i uint + + var v, s Element + + // Since u,v are updated every other iteration, we must make sure we terminate after evenly many iterations + // This also lets us get away with half as many updates to u,v + // To make this constant-time-ish, replace the condition with i < invIterationsN + for i = 0; i&1 == 1 || !a.IsZero(); i++ { + n := max(a.BitLen(), b.BitLen()) + aApprox, bApprox := approximate(&a, n), approximate(&b, n) + + // f₀, g₀, f₁, g₁ = 1, 0, 0, 1 + c0, c1 = updateFactorIdentityMatrixRow0, updateFactorIdentityMatrixRow1 + + for j := 0; j < approxLowBitsN; j++ { + + // -2ʲ < f₀, f₁ ≤ 2ʲ + // |f₀| + |f₁| < 2ʲ⁺¹ + + if aApprox&1 == 0 { + aApprox /= 2 + } else { + s, borrow := bits.Sub64(aApprox, bApprox, 0) + if borrow == 1 { + s = bApprox - aApprox + bApprox = aApprox + c0, c1 = c1, c0 + // invariants unchanged + } + + aApprox = s / 2 + c0 = c0 - c1 + + // Now |f₀| < 2ʲ⁺¹ ≤ 2ʲ⁺¹ (only the weaker inequality is needed, strictly speaking) + // Started with f₀ > -2ʲ and f₁ ≤ 2ʲ, so f₀ - f₁ > -2ʲ⁺¹ + // Invariants unchanged for f₁ + } + + c1 *= 2 + // -2ʲ⁺¹ < f₁ ≤ 2ʲ⁺¹ + // So now |f₀| + |f₁| < 2ʲ⁺² + } + + s = a + + var g0 int64 + // from this point on c0 aliases for f0 + c0, g0 = updateFactorsDecompose(c0) + aHi := a.linearCombNonModular(&s, c0, &b, g0) + if aHi&signBitSelector != 0 { + // if aHi < 0 + c0, g0 = -c0, -g0 + aHi = negL(&a, aHi) + } + // right-shift a by k-1 bits + a[0] = (a[0] >> approxLowBitsN) | ((a[1]) << approxHighBitsN) + a[1] = (a[1] >> approxLowBitsN) | ((a[2]) << approxHighBitsN) + a[2] = (a[2] >> approxLowBitsN) | ((a[3]) << approxHighBitsN) + a[3] = (a[3] >> approxLowBitsN) | ((a[4]) << approxHighBitsN) + a[4] = (a[4] >> approxLowBitsN) | ((a[5]) << approxHighBitsN) + a[5] = (a[5] >> approxLowBitsN) | (aHi << approxHighBitsN) + + var f1 int64 + // from this point on c1 aliases for g0 + f1, c1 = updateFactorsDecompose(c1) + bHi := b.linearCombNonModular(&s, f1, &b, c1) + if bHi&signBitSelector != 0 { + // if bHi < 0 + f1, c1 = -f1, -c1 + bHi = negL(&b, bHi) + } + // right-shift b by k-1 bits + b[0] = (b[0] >> approxLowBitsN) | ((b[1]) << approxHighBitsN) + b[1] = (b[1] >> approxLowBitsN) | ((b[2]) << approxHighBitsN) + b[2] = (b[2] >> approxLowBitsN) | ((b[3]) << approxHighBitsN) + b[3] = (b[3] >> approxLowBitsN) | ((b[4]) << approxHighBitsN) + b[4] = (b[4] >> approxLowBitsN) | ((b[5]) << approxHighBitsN) + b[5] = (b[5] >> approxLowBitsN) | (bHi << approxHighBitsN) + + if i&1 == 1 { + // Combine current update factors with previously stored ones + // [F₀, G₀; F₁, G₁] ← [f₀, g₀; f₁, g₁] [pf₀, pg₀; pf₁, pg₁], with capital letters denoting new combined values + // We get |F₀| = | f₀pf₀ + g₀pf₁ | ≤ |f₀pf₀| + |g₀pf₁| = |f₀| |pf₀| + |g₀| |pf₁| ≤ 2ᵏ⁻¹|pf₀| + 2ᵏ⁻¹|pf₁| + // = 2ᵏ⁻¹ (|pf₀| + |pf₁|) < 2ᵏ⁻¹ 2ᵏ = 2²ᵏ⁻¹ + // So |F₀| < 2²ᵏ⁻¹ meaning it fits in a 2k-bit signed register + + // c₀ aliases f₀, c₁ aliases g₁ + c0, g0, f1, c1 = c0*pf0+g0*pf1, + c0*pg0+g0*pg1, + f1*pf0+c1*pf1, + f1*pg0+c1*pg1 + + s = u + + // 0 ≤ u, v < 2²⁵⁵ + // |F₀|, |G₀| < 2⁶³ + u.linearComb(&u, c0, &v, g0) + // |F₁|, |G₁| < 2⁶³ + v.linearComb(&s, f1, &v, c1) + + } else { + // Save update factors + pf0, pg0, pf1, pg1 = c0, g0, f1, c1 + } + } + + // For every iteration that we miss, v is not being multiplied by 2ᵏ⁻² + const pSq uint64 = 1 << (2 * (k - 1)) + a = Element{pSq} + // If the function is constant-time ish, this loop will not run (no need to take it out explicitly) + for ; i < invIterationsN; i += 2 { + // could optimize further with mul by word routine or by pre-computing a table since with k=26, + // we would multiply by pSq up to 13times; + // on x86, the assembly routine outperforms generic code for mul by word + // on arm64, we may loose up to ~5% for 6 limbs + v.Mul(&v, &a) + } + + u.Set(x) // for correctness check + + z.Mul(&v, &Element{ + inversionCorrectionFactorWord0, + inversionCorrectionFactorWord1, + inversionCorrectionFactorWord2, + inversionCorrectionFactorWord3, + inversionCorrectionFactorWord4, + inversionCorrectionFactorWord5, + }) + + // correctness check + v.Mul(&u, z) + if !v.IsOne() && !u.IsZero() { + return z.inverseExp(u) + } + + return z +} + +// inverseExp computes z = x⁻¹ (mod q) = x**(q-2) (mod q) +func (z *Element) inverseExp(x Element) *Element { + // e == q-2 + e := Modulus() + e.Sub(e, big.NewInt(2)) + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// approximate a big number x into a single 64 bit word using its uppermost and lowermost bits +// if x fits in a word as is, no approximation necessary +func approximate(x *Element, nBits int) uint64 { + + if nBits <= 64 { + return x[0] + } + + const mask = (uint64(1) << (k - 1)) - 1 // k-1 ones + lo := mask & x[0] + + hiWordIndex := (nBits - 1) / 64 + + hiWordBitsAvailable := nBits - hiWordIndex*64 + hiWordBitsUsed := min(hiWordBitsAvailable, approxHighBitsN) + + mask_ := uint64(^((1 << (hiWordBitsAvailable - hiWordBitsUsed)) - 1)) + hi := (x[hiWordIndex] & mask_) << (64 - hiWordBitsAvailable) + + mask_ = ^(1<<(approxLowBitsN+hiWordBitsUsed) - 1) + mid := (mask_ & x[hiWordIndex-1]) >> hiWordBitsUsed + + return lo | mid | hi +} + +// linearComb z = xC * x + yC * y; +// 0 ≤ x, y < 2³⁸¹ +// |xC|, |yC| < 2⁶³ +func (z *Element) linearComb(x *Element, xC int64, y *Element, yC int64) { + // | (hi, z) | < 2 * 2⁶³ * 2³⁸¹ = 2⁴⁴⁵ + // therefore | hi | < 2⁶¹ ≤ 2⁶³ + hi := z.linearCombNonModular(x, xC, y, yC) + z.montReduceSigned(z, hi) +} + +// montReduceSigned z = (xHi * r + x) * r⁻¹ using the SOS algorithm +// Requires |xHi| < 2⁶³. Most significant bit of xHi is the sign bit. +func (z *Element) montReduceSigned(x *Element, xHi uint64) { + const signBitRemover = ^signBitSelector + mustNeg := xHi&signBitSelector != 0 + // the SOS implementation requires that most significant bit is 0 + // Let X be xHi*r + x + // If X is negative we would have initially stored it as 2⁶⁴ r + X (à la 2's complement) + xHi &= signBitRemover + // with this a negative X is now represented as 2⁶³ r + X + + var t [2*Limbs - 1]uint64 + var C uint64 + + m := x[0] * qInvNeg + + C = madd0(m, q0, x[0]) + C, t[1] = madd2(m, q1, x[1], C) + C, t[2] = madd2(m, q2, x[2], C) + C, t[3] = madd2(m, q3, x[3], C) + C, t[4] = madd2(m, q4, x[4], C) + C, t[5] = madd2(m, q5, x[5], C) + + // m * qElement[5] ≤ (2⁶⁴ - 1) * (2⁶³ - 1) = 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + // x[5] + C ≤ 2*(2⁶⁴ - 1) = 2⁶⁵ - 2 + // On LHS, (C, t[5]) ≤ 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + 2⁶⁵ - 2 = 2¹²⁷ + 2⁶³ - 1 + // So on LHS, C ≤ 2⁶³ + t[6] = xHi + C + // xHi + C < 2⁶³ + 2⁶³ = 2⁶⁴ + + // + { + const i = 1 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 2 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 3 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 4 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + C, t[i+4] = madd2(m, q4, t[i+4], C) + C, t[i+5] = madd2(m, q5, t[i+5], C) + + t[i+Limbs] += C + } + { + const i = 5 + m := t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, z[0] = madd2(m, q1, t[i+1], C) + C, z[1] = madd2(m, q2, t[i+2], C) + C, z[2] = madd2(m, q3, t[i+3], C) + C, z[3] = madd2(m, q4, t[i+4], C) + z[5], z[4] = madd2(m, q5, t[i+5], C) + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + // + + if mustNeg { + // We have computed ( 2⁶³ r + X ) r⁻¹ = 2⁶³ + X r⁻¹ instead + var b uint64 + z[0], b = bits.Sub64(z[0], signBitSelector, 0) + z[1], b = bits.Sub64(z[1], 0, b) + z[2], b = bits.Sub64(z[2], 0, b) + z[3], b = bits.Sub64(z[3], 0, b) + z[4], b = bits.Sub64(z[4], 0, b) + z[5], b = bits.Sub64(z[5], 0, b) + + // Occurs iff x == 0 && xHi < 0, i.e. X = rX' for -2⁶³ ≤ X' < 0 + + if b != 0 { + // z[5] = -1 + // negative: add q + const neg1 = 0xFFFFFFFFFFFFFFFF + + var carry uint64 + + z[0], carry = bits.Add64(z[0], q0, 0) + z[1], carry = bits.Add64(z[1], q1, carry) + z[2], carry = bits.Add64(z[2], q2, carry) + z[3], carry = bits.Add64(z[3], q3, carry) + z[4], carry = bits.Add64(z[4], q4, carry) + z[5], _ = bits.Add64(neg1, q5, carry) + } + } +} + +const ( + updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) + updateFactorIdentityMatrixRow0 = 1 + updateFactorIdentityMatrixRow1 = 1 << 32 +) + +func updateFactorsDecompose(c int64) (int64, int64) { + c += updateFactorsConversionBias + const low32BitsFilter int64 = 0xFFFFFFFF + f := c&low32BitsFilter - 0x7FFFFFFF + g := c>>32&low32BitsFilter - 0x7FFFFFFF + return f, g +} + +// negL negates in place [x | xHi] and return the new most significant word xHi +func negL(x *Element, xHi uint64) uint64 { + var b uint64 + + x[0], b = bits.Sub64(0, x[0], 0) + x[1], b = bits.Sub64(0, x[1], b) + x[2], b = bits.Sub64(0, x[2], b) + x[3], b = bits.Sub64(0, x[3], b) + x[4], b = bits.Sub64(0, x[4], b) + x[5], b = bits.Sub64(0, x[5], b) + xHi, _ = bits.Sub64(0, xHi, b) + + return xHi +} + +// mulWNonModular multiplies by one word in non-montgomery, without reducing +func (z *Element) mulWNonModular(x *Element, y int64) uint64 { + + // w := abs(y) + m := y >> 63 + w := uint64((y ^ m) - m) + + var c uint64 + c, z[0] = bits.Mul64(x[0], w) + c, z[1] = madd1(x[1], w, c) + c, z[2] = madd1(x[2], w, c) + c, z[3] = madd1(x[3], w, c) + c, z[4] = madd1(x[4], w, c) + c, z[5] = madd1(x[5], w, c) + + if y < 0 { + c = negL(z, c) + } + + return c +} + +// linearCombNonModular computes a linear combination without modular reduction +func (z *Element) linearCombNonModular(x *Element, xC int64, y *Element, yC int64) uint64 { + var yTimes Element + + yHi := yTimes.mulWNonModular(y, yC) + xHi := z.mulWNonModular(x, xC) + + var carry uint64 + z[0], carry = bits.Add64(z[0], yTimes[0], 0) + z[1], carry = bits.Add64(z[1], yTimes[1], carry) + z[2], carry = bits.Add64(z[2], yTimes[2], carry) + z[3], carry = bits.Add64(z[3], yTimes[3], carry) + z[4], carry = bits.Add64(z[4], yTimes[4], carry) + z[5], carry = bits.Add64(z[5], yTimes[5], carry) + + yHi, _ = bits.Add64(xHi, yHi, carry) + + return yHi +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_exp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_exp.go new file mode 100644 index 00000000000..4d7fafa0a1a --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_exp.go @@ -0,0 +1,1100 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +// expBySqrtExp is equivalent to z.Exp(x, 680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaab) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expBySqrtExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _100 = 2*_10 + // _1000 = 2*_100 + // _1001 = 1 + _1000 + // _1011 = _10 + _1001 + // _1100 = 1 + _1011 + // _10001 = _1000 + _1001 + // _10100 = _1000 + _1100 + // _10110 = _10 + _10100 + // _11001 = _1000 + _10001 + // _11010 = 1 + _11001 + // _101011 = _10001 + _11010 + // _110100 = _1001 + _101011 + // _110111 = _1100 + _101011 + // _1001101 = _10110 + _110111 + // _1001111 = _10 + _1001101 + // _1010101 = _1000 + _1001101 + // _1011101 = _1000 + _1010101 + // _1100111 = _11010 + _1001101 + // _1101001 = _10 + _1100111 + // _1110111 = _11010 + _1011101 + // _1111011 = _100 + _1110111 + // _10001001 = _110100 + _1010101 + // _10010101 = _1100 + _10001001 + // _10010111 = _10 + _10010101 + // _10101001 = _10100 + _10010101 + // _10110001 = _1000 + _10101001 + // _10111111 = _10110 + _10101001 + // _11000011 = _100 + _10111111 + // _11010000 = _10001 + _10111111 + // _11010111 = _10100 + _11000011 + // _11100001 = _10001 + _11010000 + // _11100101 = _100 + _11100001 + // _11101011 = _10100 + _11010111 + // _11110101 = _10100 + _11100001 + // _11111111 = _10100 + _11101011 + // i58 = ((_10111111 + _11100001) << 8 + _10001) << 11 + _11110101 + // i86 = ((i58 << 11 + _11100101) << 8 + _11111111) << 7 + // i108 = ((_1001101 + i86) << 9 + _1101001) << 10 + _10110001 + // i132 = ((i108 << 7 + _1011101) << 9 + _1111011) << 6 + // i155 = ((_11001 + i132) << 11 + _1101001) << 9 + _11101011 + // i183 = ((i155 << 10 + _11010111) << 6 + _11001) << 10 + // i206 = ((_1110111 + i183) << 9 + _10010111) << 11 + _1001111 + // i236 = ((i206 << 10 + _11100001) << 9 + _10001001) << 9 + // i257 = ((_10111111 + i236) << 8 + _1100111) << 10 + _11000011 + // i285 = ((i257 << 9 + _10010101) << 12 + _1111011) << 5 + // i306 = ((_1011 + i285) << 11 + _1111011) << 7 + _1001 + // i338 = ((i306 << 13 + _11110101) << 9 + _10111111) << 8 + // i360 = ((_11111111 + i338) << 8 + _11101011) << 11 + _10101001 + // i384 = ((i360 << 8 + _11111111) << 8 + _11111111) << 6 + // i406 = ((_110111 + i384) << 10 + _11111111) << 9 + _11111111 + // i432 = ((i406 << 8 + _11111111) << 8 + _11111111) << 8 + // return ((_11111111 + i432) << 7 + _1010101) << 7 + _101011 + // + // Operations: 373 squares 76 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + t12 = new(Element) + t13 = new(Element) + t14 = new(Element) + t15 = new(Element) + t16 = new(Element) + t17 = new(Element) + t18 = new(Element) + t19 = new(Element) + t20 = new(Element) + t21 = new(Element) + t22 = new(Element) + t23 = new(Element) + t24 = new(Element) + t25 = new(Element) + t26 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26 Element + // Step 1: t3 = x^0x2 + t3.Square(&x) + + // Step 2: t4 = x^0x4 + t4.Square(t3) + + // Step 3: t6 = x^0x8 + t6.Square(t4) + + // Step 4: t7 = x^0x9 + t7.Mul(&x, t6) + + // Step 5: t9 = x^0xb + t9.Mul(t3, t7) + + // Step 6: t10 = x^0xc + t10.Mul(&x, t9) + + // Step 7: t25 = x^0x11 + t25.Mul(t6, t7) + + // Step 8: t1 = x^0x14 + t1.Mul(t6, t10) + + // Step 9: t5 = x^0x16 + t5.Mul(t3, t1) + + // Step 10: t18 = x^0x19 + t18.Mul(t6, t25) + + // Step 11: t8 = x^0x1a + t8.Mul(&x, t18) + + // Step 12: z = x^0x2b + z.Mul(t25, t8) + + // Step 13: t11 = x^0x34 + t11.Mul(t7, z) + + // Step 14: t2 = x^0x37 + t2.Mul(t10, z) + + // Step 15: t23 = x^0x4d + t23.Mul(t5, t2) + + // Step 16: t15 = x^0x4f + t15.Mul(t3, t23) + + // Step 17: t0 = x^0x55 + t0.Mul(t6, t23) + + // Step 18: t21 = x^0x5d + t21.Mul(t6, t0) + + // Step 19: t12 = x^0x67 + t12.Mul(t8, t23) + + // Step 20: t20 = x^0x69 + t20.Mul(t3, t12) + + // Step 21: t17 = x^0x77 + t17.Mul(t8, t21) + + // Step 22: t8 = x^0x7b + t8.Mul(t4, t17) + + // Step 23: t13 = x^0x89 + t13.Mul(t11, t0) + + // Step 24: t10 = x^0x95 + t10.Mul(t10, t13) + + // Step 25: t16 = x^0x97 + t16.Mul(t3, t10) + + // Step 26: t3 = x^0xa9 + t3.Mul(t1, t10) + + // Step 27: t22 = x^0xb1 + t22.Mul(t6, t3) + + // Step 28: t5 = x^0xbf + t5.Mul(t5, t3) + + // Step 29: t11 = x^0xc3 + t11.Mul(t4, t5) + + // Step 30: t6 = x^0xd0 + t6.Mul(t25, t5) + + // Step 31: t19 = x^0xd7 + t19.Mul(t1, t11) + + // Step 32: t14 = x^0xe1 + t14.Mul(t25, t6) + + // Step 33: t24 = x^0xe5 + t24.Mul(t4, t14) + + // Step 34: t4 = x^0xeb + t4.Mul(t1, t19) + + // Step 35: t6 = x^0xf5 + t6.Mul(t1, t14) + + // Step 36: t1 = x^0xff + t1.Mul(t1, t4) + + // Step 37: t26 = x^0x1a0 + t26.Mul(t5, t14) + + // Step 45: t26 = x^0x1a000 + for s := 0; s < 8; s++ { + t26.Square(t26) + } + + // Step 46: t25 = x^0x1a011 + t25.Mul(t25, t26) + + // Step 57: t25 = x^0xd008800 + for s := 0; s < 11; s++ { + t25.Square(t25) + } + + // Step 58: t25 = x^0xd0088f5 + t25.Mul(t6, t25) + + // Step 69: t25 = x^0x680447a800 + for s := 0; s < 11; s++ { + t25.Square(t25) + } + + // Step 70: t24 = x^0x680447a8e5 + t24.Mul(t24, t25) + + // Step 78: t24 = x^0x680447a8e500 + for s := 0; s < 8; s++ { + t24.Square(t24) + } + + // Step 79: t24 = x^0x680447a8e5ff + t24.Mul(t1, t24) + + // Step 86: t24 = x^0x340223d472ff80 + for s := 0; s < 7; s++ { + t24.Square(t24) + } + + // Step 87: t23 = x^0x340223d472ffcd + t23.Mul(t23, t24) + + // Step 96: t23 = x^0x680447a8e5ff9a00 + for s := 0; s < 9; s++ { + t23.Square(t23) + } + + // Step 97: t23 = x^0x680447a8e5ff9a69 + t23.Mul(t20, t23) + + // Step 107: t23 = x^0x1a0111ea397fe69a400 + for s := 0; s < 10; s++ { + t23.Square(t23) + } + + // Step 108: t22 = x^0x1a0111ea397fe69a4b1 + t22.Mul(t22, t23) + + // Step 115: t22 = x^0xd0088f51cbff34d25880 + for s := 0; s < 7; s++ { + t22.Square(t22) + } + + // Step 116: t21 = x^0xd0088f51cbff34d258dd + t21.Mul(t21, t22) + + // Step 125: t21 = x^0x1a0111ea397fe69a4b1ba00 + for s := 0; s < 9; s++ { + t21.Square(t21) + } + + // Step 126: t21 = x^0x1a0111ea397fe69a4b1ba7b + t21.Mul(t8, t21) + + // Step 132: t21 = x^0x680447a8e5ff9a692c6e9ec0 + for s := 0; s < 6; s++ { + t21.Square(t21) + } + + // Step 133: t21 = x^0x680447a8e5ff9a692c6e9ed9 + t21.Mul(t18, t21) + + // Step 144: t21 = x^0x340223d472ffcd3496374f6c800 + for s := 0; s < 11; s++ { + t21.Square(t21) + } + + // Step 145: t20 = x^0x340223d472ffcd3496374f6c869 + t20.Mul(t20, t21) + + // Step 154: t20 = x^0x680447a8e5ff9a692c6e9ed90d200 + for s := 0; s < 9; s++ { + t20.Square(t20) + } + + // Step 155: t20 = x^0x680447a8e5ff9a692c6e9ed90d2eb + t20.Mul(t4, t20) + + // Step 165: t20 = x^0x1a0111ea397fe69a4b1ba7b6434bac00 + for s := 0; s < 10; s++ { + t20.Square(t20) + } + + // Step 166: t19 = x^0x1a0111ea397fe69a4b1ba7b6434bacd7 + t19.Mul(t19, t20) + + // Step 172: t19 = x^0x680447a8e5ff9a692c6e9ed90d2eb35c0 + for s := 0; s < 6; s++ { + t19.Square(t19) + } + + // Step 173: t18 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d9 + t18.Mul(t18, t19) + + // Step 183: t18 = x^0x1a0111ea397fe69a4b1ba7b6434bacd76400 + for s := 0; s < 10; s++ { + t18.Square(t18) + } + + // Step 184: t17 = x^0x1a0111ea397fe69a4b1ba7b6434bacd76477 + t17.Mul(t17, t18) + + // Step 193: t17 = x^0x340223d472ffcd3496374f6c869759aec8ee00 + for s := 0; s < 9; s++ { + t17.Square(t17) + } + + // Step 194: t16 = x^0x340223d472ffcd3496374f6c869759aec8ee97 + t16.Mul(t16, t17) + + // Step 205: t16 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b800 + for s := 0; s < 11; s++ { + t16.Square(t16) + } + + // Step 206: t15 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f + t15.Mul(t15, t16) + + // Step 216: t15 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13c00 + for s := 0; s < 10; s++ { + t15.Square(t15) + } + + // Step 217: t14 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce1 + t14.Mul(t14, t15) + + // Step 226: t14 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c200 + for s := 0; s < 9; s++ { + t14.Square(t14) + } + + // Step 227: t13 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c289 + t13.Mul(t13, t14) + + // Step 236: t13 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f3851200 + for s := 0; s < 9; s++ { + t13.Square(t13) + } + + // Step 237: t13 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf + t13.Mul(t5, t13) + + // Step 245: t13 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf00 + for s := 0; s < 8; s++ { + t13.Square(t13) + } + + // Step 246: t12 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf67 + t12.Mul(t12, t13) + + // Step 256: t12 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9c00 + for s := 0; s < 10; s++ { + t12.Square(t12) + } + + // Step 257: t11 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc3 + t11.Mul(t11, t12) + + // Step 266: t11 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb398600 + for s := 0; s < 9; s++ { + t11.Square(t11) + } + + // Step 267: t10 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb398695 + t10.Mul(t10, t11) + + // Step 279: t10 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb398695000 + for s := 0; s < 12; s++ { + t10.Square(t10) + } + + // Step 280: t10 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b + t10.Mul(t8, t10) + + // Step 285: t10 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f60 + for s := 0; s < 5; s++ { + t10.Square(t10) + } + + // Step 286: t9 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b + t9.Mul(t9, t10) + + // Step 297: t9 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b5800 + for s := 0; s < 11; s++ { + t9.Square(t9) + } + + // Step 298: t8 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b + t8.Mul(t8, t9) + + // Step 305: t8 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d80 + for s := 0; s < 7; s++ { + t8.Square(t8) + } + + // Step 306: t7 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d89 + t7.Mul(t7, t8) + + // Step 319: t7 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b12000 + for s := 0; s < 13; s++ { + t7.Square(t7) + } + + // Step 320: t6 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f5 + t6.Mul(t6, t7) + + // Step 329: t6 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241ea00 + for s := 0; s < 9; s++ { + t6.Square(t6) + } + + // Step 330: t5 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabf + t5.Mul(t5, t6) + + // Step 338: t5 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabf00 + for s := 0; s < 8; s++ { + t5.Square(t5) + } + + // Step 339: t5 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfff + t5.Mul(t1, t5) + + // Step 347: t5 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfff00 + for s := 0; s < 8; s++ { + t5.Square(t5) + } + + // Step 348: t4 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb + t4.Mul(t4, t5) + + // Step 359: t4 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff5800 + for s := 0; s < 11; s++ { + t4.Square(t4) + } + + // Step 360: t3 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9 + t3.Mul(t3, t4) + + // Step 368: t3 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a900 + for s := 0; s < 8; s++ { + t3.Square(t3) + } + + // Step 369: t3 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ff + t3.Mul(t1, t3) + + // Step 377: t3 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ff00 + for s := 0; s < 8; s++ { + t3.Square(t3) + } + + // Step 378: t3 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffff + t3.Mul(t1, t3) + + // Step 384: t3 = x^0x340223d472ffcd3496374f6c869759aec8ee9709e70a257ece61a541ed61ec483d57fffd62a7fffc0 + for s := 0; s < 6; s++ { + t3.Square(t3) + } + + // Step 385: t2 = x^0x340223d472ffcd3496374f6c869759aec8ee9709e70a257ece61a541ed61ec483d57fffd62a7ffff7 + t2.Mul(t2, t3) + + // Step 395: t2 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdc00 + for s := 0; s < 10; s++ { + t2.Square(t2) + } + + // Step 396: t2 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff + t2.Mul(t1, t2) + + // Step 405: t2 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9fe00 + for s := 0; s < 9; s++ { + t2.Square(t2) + } + + // Step 406: t2 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feff + t2.Mul(t1, t2) + + // Step 414: t2 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feff00 + for s := 0; s < 8; s++ { + t2.Square(t2) + } + + // Step 415: t2 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffff + t2.Mul(t1, t2) + + // Step 423: t2 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffff00 + for s := 0; s < 8; s++ { + t2.Square(t2) + } + + // Step 424: t2 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffff + t2.Mul(t1, t2) + + // Step 432: t2 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffff00 + for s := 0; s < 8; s++ { + t2.Square(t2) + } + + // Step 433: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffff + t1.Mul(t1, t2) + + // Step 440: t1 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffff80 + for s := 0; s < 7; s++ { + t1.Square(t1) + } + + // Step 441: t0 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd5 + t0.Mul(t0, t1) + + // Step 448: t0 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffea80 + for s := 0; s < 7; s++ { + t0.Square(t0) + } + + // Step 449: z = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d8907aaffffac54ffffee7fbfffffffeaab + z.Mul(z, t0) + + return z +} + +// expByLegendreExp is equivalent to z.Exp(x, d0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expByLegendreExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _100 = 2*_10 + // _1000 = 2*_100 + // _1001 = 1 + _1000 + // _1011 = _10 + _1001 + // _1101 = _10 + _1011 + // _10001 = _100 + _1101 + // _10100 = _1001 + _1011 + // _11001 = _1000 + _10001 + // _11010 = 1 + _11001 + // _110100 = 2*_11010 + // _110110 = _10 + _110100 + // _110111 = 1 + _110110 + // _1001101 = _11001 + _110100 + // _1001111 = _10 + _1001101 + // _1010101 = _1000 + _1001101 + // _1011101 = _1000 + _1010101 + // _1100111 = _11010 + _1001101 + // _1101001 = _10 + _1100111 + // _1110111 = _11010 + _1011101 + // _1111011 = _100 + _1110111 + // _10001001 = _110100 + _1010101 + // _10010101 = _11010 + _1111011 + // _10010111 = _10 + _10010101 + // _10101001 = _10100 + _10010101 + // _10110001 = _1000 + _10101001 + // _10111111 = _110110 + _10001001 + // _11000011 = _100 + _10111111 + // _11010000 = _1101 + _11000011 + // _11010111 = _10100 + _11000011 + // _11100001 = _10001 + _11010000 + // _11100101 = _100 + _11100001 + // _11101011 = _10100 + _11010111 + // _11110101 = _10100 + _11100001 + // _11111111 = _10100 + _11101011 + // i57 = ((_10111111 + _11100001) << 8 + _10001) << 11 + _11110101 + // i85 = ((i57 << 11 + _11100101) << 8 + _11111111) << 7 + // i107 = ((_1001101 + i85) << 9 + _1101001) << 10 + _10110001 + // i131 = ((i107 << 7 + _1011101) << 9 + _1111011) << 6 + // i154 = ((_11001 + i131) << 11 + _1101001) << 9 + _11101011 + // i182 = ((i154 << 10 + _11010111) << 6 + _11001) << 10 + // i205 = ((_1110111 + i182) << 9 + _10010111) << 11 + _1001111 + // i235 = ((i205 << 10 + _11100001) << 9 + _10001001) << 9 + // i256 = ((_10111111 + i235) << 8 + _1100111) << 10 + _11000011 + // i284 = ((i256 << 9 + _10010101) << 12 + _1111011) << 5 + // i305 = ((_1011 + i284) << 11 + _1111011) << 7 + _1001 + // i337 = ((i305 << 13 + _11110101) << 9 + _10111111) << 8 + // i359 = ((_11111111 + i337) << 8 + _11101011) << 11 + _10101001 + // i383 = ((i359 << 8 + _11111111) << 8 + _11111111) << 6 + // i405 = ((_110111 + i383) << 10 + _11111111) << 9 + _11111111 + // i431 = ((i405 << 8 + _11111111) << 8 + _11111111) << 8 + // return ((_11111111 + i431) << 7 + _1010101) << 8 + _1010101 + // + // Operations: 375 squares 74 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + t12 = new(Element) + t13 = new(Element) + t14 = new(Element) + t15 = new(Element) + t16 = new(Element) + t17 = new(Element) + t18 = new(Element) + t19 = new(Element) + t20 = new(Element) + t21 = new(Element) + t22 = new(Element) + t23 = new(Element) + t24 = new(Element) + t25 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25 Element + // Step 1: t2 = x^0x2 + t2.Square(&x) + + // Step 2: t3 = x^0x4 + t3.Square(t2) + + // Step 3: t10 = x^0x8 + t10.Square(t3) + + // Step 4: t6 = x^0x9 + t6.Mul(&x, t10) + + // Step 5: t8 = x^0xb + t8.Mul(t2, t6) + + // Step 6: t5 = x^0xd + t5.Mul(t2, t8) + + // Step 7: t24 = x^0x11 + t24.Mul(t3, t5) + + // Step 8: t0 = x^0x14 + t0.Mul(t6, t8) + + // Step 9: t17 = x^0x19 + t17.Mul(t10, t24) + + // Step 10: t9 = x^0x1a + t9.Mul(&x, t17) + + // Step 11: t12 = x^0x34 + t12.Square(t9) + + // Step 12: t4 = x^0x36 + t4.Mul(t2, t12) + + // Step 13: t1 = x^0x37 + t1.Mul(&x, t4) + + // Step 14: t22 = x^0x4d + t22.Mul(t17, t12) + + // Step 15: t14 = x^0x4f + t14.Mul(t2, t22) + + // Step 16: z = x^0x55 + z.Mul(t10, t22) + + // Step 17: t20 = x^0x5d + t20.Mul(t10, z) + + // Step 18: t11 = x^0x67 + t11.Mul(t9, t22) + + // Step 19: t19 = x^0x69 + t19.Mul(t2, t11) + + // Step 20: t16 = x^0x77 + t16.Mul(t9, t20) + + // Step 21: t7 = x^0x7b + t7.Mul(t3, t16) + + // Step 22: t12 = x^0x89 + t12.Mul(t12, z) + + // Step 23: t9 = x^0x95 + t9.Mul(t9, t7) + + // Step 24: t15 = x^0x97 + t15.Mul(t2, t9) + + // Step 25: t2 = x^0xa9 + t2.Mul(t0, t9) + + // Step 26: t21 = x^0xb1 + t21.Mul(t10, t2) + + // Step 27: t4 = x^0xbf + t4.Mul(t4, t12) + + // Step 28: t10 = x^0xc3 + t10.Mul(t3, t4) + + // Step 29: t5 = x^0xd0 + t5.Mul(t5, t10) + + // Step 30: t18 = x^0xd7 + t18.Mul(t0, t10) + + // Step 31: t13 = x^0xe1 + t13.Mul(t24, t5) + + // Step 32: t23 = x^0xe5 + t23.Mul(t3, t13) + + // Step 33: t3 = x^0xeb + t3.Mul(t0, t18) + + // Step 34: t5 = x^0xf5 + t5.Mul(t0, t13) + + // Step 35: t0 = x^0xff + t0.Mul(t0, t3) + + // Step 36: t25 = x^0x1a0 + t25.Mul(t4, t13) + + // Step 44: t25 = x^0x1a000 + for s := 0; s < 8; s++ { + t25.Square(t25) + } + + // Step 45: t24 = x^0x1a011 + t24.Mul(t24, t25) + + // Step 56: t24 = x^0xd008800 + for s := 0; s < 11; s++ { + t24.Square(t24) + } + + // Step 57: t24 = x^0xd0088f5 + t24.Mul(t5, t24) + + // Step 68: t24 = x^0x680447a800 + for s := 0; s < 11; s++ { + t24.Square(t24) + } + + // Step 69: t23 = x^0x680447a8e5 + t23.Mul(t23, t24) + + // Step 77: t23 = x^0x680447a8e500 + for s := 0; s < 8; s++ { + t23.Square(t23) + } + + // Step 78: t23 = x^0x680447a8e5ff + t23.Mul(t0, t23) + + // Step 85: t23 = x^0x340223d472ff80 + for s := 0; s < 7; s++ { + t23.Square(t23) + } + + // Step 86: t22 = x^0x340223d472ffcd + t22.Mul(t22, t23) + + // Step 95: t22 = x^0x680447a8e5ff9a00 + for s := 0; s < 9; s++ { + t22.Square(t22) + } + + // Step 96: t22 = x^0x680447a8e5ff9a69 + t22.Mul(t19, t22) + + // Step 106: t22 = x^0x1a0111ea397fe69a400 + for s := 0; s < 10; s++ { + t22.Square(t22) + } + + // Step 107: t21 = x^0x1a0111ea397fe69a4b1 + t21.Mul(t21, t22) + + // Step 114: t21 = x^0xd0088f51cbff34d25880 + for s := 0; s < 7; s++ { + t21.Square(t21) + } + + // Step 115: t20 = x^0xd0088f51cbff34d258dd + t20.Mul(t20, t21) + + // Step 124: t20 = x^0x1a0111ea397fe69a4b1ba00 + for s := 0; s < 9; s++ { + t20.Square(t20) + } + + // Step 125: t20 = x^0x1a0111ea397fe69a4b1ba7b + t20.Mul(t7, t20) + + // Step 131: t20 = x^0x680447a8e5ff9a692c6e9ec0 + for s := 0; s < 6; s++ { + t20.Square(t20) + } + + // Step 132: t20 = x^0x680447a8e5ff9a692c6e9ed9 + t20.Mul(t17, t20) + + // Step 143: t20 = x^0x340223d472ffcd3496374f6c800 + for s := 0; s < 11; s++ { + t20.Square(t20) + } + + // Step 144: t19 = x^0x340223d472ffcd3496374f6c869 + t19.Mul(t19, t20) + + // Step 153: t19 = x^0x680447a8e5ff9a692c6e9ed90d200 + for s := 0; s < 9; s++ { + t19.Square(t19) + } + + // Step 154: t19 = x^0x680447a8e5ff9a692c6e9ed90d2eb + t19.Mul(t3, t19) + + // Step 164: t19 = x^0x1a0111ea397fe69a4b1ba7b6434bac00 + for s := 0; s < 10; s++ { + t19.Square(t19) + } + + // Step 165: t18 = x^0x1a0111ea397fe69a4b1ba7b6434bacd7 + t18.Mul(t18, t19) + + // Step 171: t18 = x^0x680447a8e5ff9a692c6e9ed90d2eb35c0 + for s := 0; s < 6; s++ { + t18.Square(t18) + } + + // Step 172: t17 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d9 + t17.Mul(t17, t18) + + // Step 182: t17 = x^0x1a0111ea397fe69a4b1ba7b6434bacd76400 + for s := 0; s < 10; s++ { + t17.Square(t17) + } + + // Step 183: t16 = x^0x1a0111ea397fe69a4b1ba7b6434bacd76477 + t16.Mul(t16, t17) + + // Step 192: t16 = x^0x340223d472ffcd3496374f6c869759aec8ee00 + for s := 0; s < 9; s++ { + t16.Square(t16) + } + + // Step 193: t15 = x^0x340223d472ffcd3496374f6c869759aec8ee97 + t15.Mul(t15, t16) + + // Step 204: t15 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b800 + for s := 0; s < 11; s++ { + t15.Square(t15) + } + + // Step 205: t14 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f + t14.Mul(t14, t15) + + // Step 215: t14 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13c00 + for s := 0; s < 10; s++ { + t14.Square(t14) + } + + // Step 216: t13 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce1 + t13.Mul(t13, t14) + + // Step 225: t13 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c200 + for s := 0; s < 9; s++ { + t13.Square(t13) + } + + // Step 226: t12 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c289 + t12.Mul(t12, t13) + + // Step 235: t12 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f3851200 + for s := 0; s < 9; s++ { + t12.Square(t12) + } + + // Step 236: t12 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf + t12.Mul(t4, t12) + + // Step 244: t12 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf00 + for s := 0; s < 8; s++ { + t12.Square(t12) + } + + // Step 245: t11 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf67 + t11.Mul(t11, t12) + + // Step 255: t11 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9c00 + for s := 0; s < 10; s++ { + t11.Square(t11) + } + + // Step 256: t10 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc3 + t10.Mul(t10, t11) + + // Step 265: t10 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb398600 + for s := 0; s < 9; s++ { + t10.Square(t10) + } + + // Step 266: t9 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb398695 + t9.Mul(t9, t10) + + // Step 278: t9 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb398695000 + for s := 0; s < 12; s++ { + t9.Square(t9) + } + + // Step 279: t9 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b + t9.Mul(t7, t9) + + // Step 284: t9 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f60 + for s := 0; s < 5; s++ { + t9.Square(t9) + } + + // Step 285: t8 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b + t8.Mul(t8, t9) + + // Step 296: t8 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b5800 + for s := 0; s < 11; s++ { + t8.Square(t8) + } + + // Step 297: t7 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b + t7.Mul(t7, t8) + + // Step 304: t7 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d80 + for s := 0; s < 7; s++ { + t7.Square(t7) + } + + // Step 305: t6 = x^0x680447a8e5ff9a692c6e9ed90d2eb35d91dd2e13ce144afd9cc34a83dac3d89 + t6.Mul(t6, t7) + + // Step 318: t6 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b12000 + for s := 0; s < 13; s++ { + t6.Square(t6) + } + + // Step 319: t5 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f5 + t5.Mul(t5, t6) + + // Step 328: t5 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241ea00 + for s := 0; s < 9; s++ { + t5.Square(t5) + } + + // Step 329: t4 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabf + t4.Mul(t4, t5) + + // Step 337: t4 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabf00 + for s := 0; s < 8; s++ { + t4.Square(t4) + } + + // Step 338: t4 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfff + t4.Mul(t0, t4) + + // Step 346: t4 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfff00 + for s := 0; s < 8; s++ { + t4.Square(t4) + } + + // Step 347: t3 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb + t3.Mul(t3, t4) + + // Step 358: t3 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff5800 + for s := 0; s < 11; s++ { + t3.Square(t3) + } + + // Step 359: t2 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9 + t2.Mul(t2, t3) + + // Step 367: t2 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a900 + for s := 0; s < 8; s++ { + t2.Square(t2) + } + + // Step 368: t2 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ff + t2.Mul(t0, t2) + + // Step 376: t2 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ff00 + for s := 0; s < 8; s++ { + t2.Square(t2) + } + + // Step 377: t2 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffff + t2.Mul(t0, t2) + + // Step 383: t2 = x^0x340223d472ffcd3496374f6c869759aec8ee9709e70a257ece61a541ed61ec483d57fffd62a7fffc0 + for s := 0; s < 6; s++ { + t2.Square(t2) + } + + // Step 384: t1 = x^0x340223d472ffcd3496374f6c869759aec8ee9709e70a257ece61a541ed61ec483d57fffd62a7ffff7 + t1.Mul(t1, t2) + + // Step 394: t1 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdc00 + for s := 0; s < 10; s++ { + t1.Square(t1) + } + + // Step 395: t1 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff + t1.Mul(t0, t1) + + // Step 404: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9fe00 + for s := 0; s < 9; s++ { + t1.Square(t1) + } + + // Step 405: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feff + t1.Mul(t0, t1) + + // Step 413: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feff00 + for s := 0; s < 8; s++ { + t1.Square(t1) + } + + // Step 414: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffff + t1.Mul(t0, t1) + + // Step 422: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffff00 + for s := 0; s < 8; s++ { + t1.Square(t1) + } + + // Step 423: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffff + t1.Mul(t0, t1) + + // Step 431: t1 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffff00 + for s := 0; s < 8; s++ { + t1.Square(t1) + } + + // Step 432: t0 = x^0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffff + t0.Mul(t0, t1) + + // Step 439: t0 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffff80 + for s := 0; s < 7; s++ { + t0.Square(t0) + } + + // Step 440: t0 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd5 + t0.Mul(z, t0) + + // Step 448: t0 = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd500 + for s := 0; s < 8; s++ { + t0.Square(t0) + } + + // Step 449: z = x^0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555 + z.Mul(z, t0) + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_mul_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_mul_amd64.s new file mode 100644 index 00000000000..9e03b1c0ace --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_mul_amd64.s @@ -0,0 +1,857 @@ +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0xb9feffffffffaaab +DATA q<>+8(SB)/8, $0x1eabfffeb153ffff +DATA q<>+16(SB)/8, $0x6730d2a0f6b0f624 +DATA q<>+24(SB)/8, $0x64774b84f38512bf +DATA q<>+32(SB)/8, $0x4b1ba7b6434bacd7 +DATA q<>+40(SB)/8, $0x1a0111ea397fe69a +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x89f3fffcfffcfffd +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +// mul(res, x, y *Element) +TEXT ·mul(SB), $24-24 + + // the algorithm is described in the Element.Mul declaration (.go) + // however, to benefit from the ADCX and ADOX carry chains + // we split the inner loops in 2: + // for i=0 to N-1 + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + A + + NO_LOCAL_POINTERS + CMPB ·supportAdx(SB), $1 + JNE l1 + MOVQ x+8(FP), R8 + + // x[0] -> R10 + // x[1] -> R11 + // x[2] -> R12 + MOVQ 0(R8), R10 + MOVQ 8(R8), R11 + MOVQ 16(R8), R12 + MOVQ y+16(FP), R13 + + // A -> BP + // t[0] -> R14 + // t[1] -> R15 + // t[2] -> CX + // t[3] -> BX + // t[4] -> SI + // t[5] -> DI + // clear the flags + XORQ AX, AX + MOVQ 0(R13), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R10, R14, R15 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R11, AX, CX + ADOXQ AX, R15 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ R12, AX, BX + ADOXQ AX, CX + + // (A,t[3]) := x[3]*y[0] + A + MULXQ 24(R8), AX, SI + ADOXQ AX, BX + + // (A,t[4]) := x[4]*y[0] + A + MULXQ 32(R8), AX, DI + ADOXQ AX, SI + + // (A,t[5]) := x[5]*y[0] + A + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 8(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 16(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 24(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 32(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // clear the flags + XORQ AX, AX + MOVQ 40(R13), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R10, AX, BP + ADOXQ AX, R14 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R15 + MULXQ R11, AX, BP + ADOXQ AX, R15 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, CX + MULXQ R12, AX, BP + ADOXQ AX, CX + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, BX + MULXQ 24(R8), AX, BP + ADOXQ AX, BX + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, SI + MULXQ 32(R8), AX, BP + ADOXQ AX, SI + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, DI + MULXQ 40(R8), AX, BP + ADOXQ AX, DI + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, R9 + ADCXQ R14, AX + MOVQ R9, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ BP, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R9,R8,R13,R10,R11,R12) + REDUCE(R14,R15,CX,BX,SI,DI,R9,R8,R13,R10,R11,R12) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET + +l1: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·_mulGeneric(SB) + RET + +TEXT ·fromMont(SB), $8-8 + NO_LOCAL_POINTERS + + // the algorithm is described here + // https://hackmd.io/@gnark/modular_multiplication + // when y = 1 we have: + // for i=0 to N-1 + // t[i] = x[i] + // for i=0 to N-1 + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + CMPB ·supportAdx(SB), $1 + JNE l2 + MOVQ res+0(FP), DX + MOVQ 0(DX), R14 + MOVQ 8(DX), R15 + MOVQ 16(DX), CX + MOVQ 24(DX), BX + MOVQ 32(DX), SI + MOVQ 40(DX), DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + XORQ DX, DX + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R14, DX + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R14, AX + MOVQ BP, R14 + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R15, R14 + MULXQ q<>+8(SB), AX, R15 + ADOXQ AX, R14 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ CX, R15 + MULXQ q<>+16(SB), AX, CX + ADOXQ AX, R15 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ BX, CX + MULXQ q<>+24(SB), AX, BX + ADOXQ AX, CX + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ SI, BX + MULXQ q<>+32(SB), AX, SI + ADOXQ AX, BX + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ DI, SI + MULXQ q<>+40(SB), AX, DI + ADOXQ AX, SI + MOVQ $0, AX + ADCXQ AX, DI + ADOXQ AX, DI + + // reduce element(R14,R15,CX,BX,SI,DI) using temp registers (R8,R9,R10,R11,R12,R13) + REDUCE(R14,R15,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13) + + MOVQ res+0(FP), AX + MOVQ R14, 0(AX) + MOVQ R15, 8(AX) + MOVQ CX, 16(AX) + MOVQ BX, 24(AX) + MOVQ SI, 32(AX) + MOVQ DI, 40(AX) + RET + +l2: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + CALL ·_fromMontGeneric(SB) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.go new file mode 100644 index 00000000000..83bba45aedf --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.go @@ -0,0 +1,107 @@ +//go:build !purego +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +//go:noescape +func MulBy3(x *Element) + +//go:noescape +func MulBy5(x *Element) + +//go:noescape +func MulBy13(x *Element) + +//go:noescape +func mul(res, x, y *Element) + +//go:noescape +func fromMont(res *Element) + +//go:noescape +func reduce(res *Element) + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +// +//go:noescape +func Butterfly(a, b *Element) + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + mul(z, x, y) + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for doc. + mul(z, x, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.s new file mode 100644 index 00000000000..830b2dd63f9 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_amd64.s @@ -0,0 +1,306 @@ +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0xb9feffffffffaaab +DATA q<>+8(SB)/8, $0x1eabfffeb153ffff +DATA q<>+16(SB)/8, $0x6730d2a0f6b0f624 +DATA q<>+24(SB)/8, $0x64774b84f38512bf +DATA q<>+32(SB)/8, $0x4b1ba7b6434bacd7 +DATA q<>+40(SB)/8, $0x1a0111ea397fe69a +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x89f3fffcfffcfffd +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +TEXT ·reduce(SB), NOSPLIT, $0-8 + MOVQ res+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy3(x *Element) +TEXT ·MulBy3(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,R9,R10,R11,R12,R13) + REDUCE(DX,CX,BX,SI,DI,R8,R15,R9,R10,R11,R12,R13) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy5(x *Element) +TEXT ·MulBy5(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,R9,R10,R11,R12,R13) + REDUCE(DX,CX,BX,SI,DI,R8,R15,R9,R10,R11,R12,R13) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R14,R15,R9,R10,R11,R12) + REDUCE(DX,CX,BX,SI,DI,R8,R14,R15,R9,R10,R11,R12) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// MulBy13(x *Element) +TEXT ·MulBy13(SB), $40-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + MOVQ 32(AX), DI + MOVQ 40(AX), R8 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R15,s0-8(SP),s1-16(SP),s2-24(SP),s3-32(SP),s4-40(SP)) + REDUCE(DX,CX,BX,SI,DI,R8,R15,s0-8(SP),s1-16(SP),s2-24(SP),s3-32(SP),s4-40(SP)) + + MOVQ DX, R15 + MOVQ CX, s0-8(SP) + MOVQ BX, s1-16(SP) + MOVQ SI, s2-24(SP) + MOVQ DI, s3-32(SP) + MOVQ R8, s4-40(SP) + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ R15, DX + ADCQ s0-8(SP), CX + ADCQ s1-16(SP), BX + ADCQ s2-24(SP), SI + ADCQ s3-32(SP), DI + ADCQ s4-40(SP), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + ADCQ 32(AX), DI + ADCQ 40(AX), R8 + + // reduce element(DX,CX,BX,SI,DI,R8) using temp registers (R9,R10,R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + MOVQ DI, 32(AX) + MOVQ R8, 40(AX) + RET + +// Butterfly(a, b *Element) sets a = a + b; b = a - b +TEXT ·Butterfly(SB), $48-16 + MOVQ a+0(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ 32(AX), R8 + MOVQ 40(AX), R9 + MOVQ CX, R10 + MOVQ BX, R11 + MOVQ SI, R12 + MOVQ DI, R13 + MOVQ R8, R14 + MOVQ R9, R15 + XORQ AX, AX + MOVQ b+8(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + ADCQ 32(DX), R8 + ADCQ 40(DX), R9 + SUBQ 0(DX), R10 + SBBQ 8(DX), R11 + SBBQ 16(DX), R12 + SBBQ 24(DX), R13 + SBBQ 32(DX), R14 + SBBQ 40(DX), R15 + MOVQ CX, s0-8(SP) + MOVQ BX, s1-16(SP) + MOVQ SI, s2-24(SP) + MOVQ DI, s3-32(SP) + MOVQ R8, s4-40(SP) + MOVQ R9, s5-48(SP) + MOVQ $0xb9feffffffffaaab, CX + MOVQ $0x1eabfffeb153ffff, BX + MOVQ $0x6730d2a0f6b0f624, SI + MOVQ $0x64774b84f38512bf, DI + MOVQ $0x4b1ba7b6434bacd7, R8 + MOVQ $0x1a0111ea397fe69a, R9 + CMOVQCC AX, CX + CMOVQCC AX, BX + CMOVQCC AX, SI + CMOVQCC AX, DI + CMOVQCC AX, R8 + CMOVQCC AX, R9 + ADDQ CX, R10 + ADCQ BX, R11 + ADCQ SI, R12 + ADCQ DI, R13 + ADCQ R8, R14 + ADCQ R9, R15 + MOVQ s0-8(SP), CX + MOVQ s1-16(SP), BX + MOVQ s2-24(SP), SI + MOVQ s3-32(SP), DI + MOVQ s4-40(SP), R8 + MOVQ s5-48(SP), R9 + MOVQ R10, 0(DX) + MOVQ R11, 8(DX) + MOVQ R12, 16(DX) + MOVQ R13, 24(DX) + MOVQ R14, 32(DX) + MOVQ R15, 40(DX) + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ a+0(FP), AX + MOVQ CX, 0(AX) + MOVQ BX, 8(AX) + MOVQ SI, 16(AX) + MOVQ DI, 24(AX) + MOVQ R8, 32(AX) + MOVQ R9, 40(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_purego.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_purego.go new file mode 100644 index 00000000000..fc10b3df30d --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element_ops_purego.go @@ -0,0 +1,745 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import "math/bits" + +// MulBy3 x *= 3 (mod q) +func MulBy3(x *Element) { + _x := *x + x.Double(x).Add(x, &_x) +} + +// MulBy5 x *= 5 (mod q) +func MulBy5(x *Element) { + _x := *x + x.Double(x).Double(x).Add(x, &_x) +} + +// MulBy13 x *= 13 (mod q) +func MulBy13(x *Element) { + var y = Element{ + 13438459813099623723, + 14459933216667336738, + 14900020990258308116, + 2941282712809091851, + 13639094935183769893, + 1835248516986607988, + } + x.Mul(x, &y) +} + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + var t0, t1, t2, t3, t4, t5 uint64 + var u0, u1, u2, u3, u4, u5 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, y[0]) + u1, t1 = bits.Mul64(v, y[1]) + u2, t2 = bits.Mul64(v, y[2]) + u3, t3 = bits.Mul64(v, y[3]) + u4, t4 = bits.Mul64(v, y[4]) + u5, t5 = bits.Mul64(v, y[5]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[4] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[5] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, y[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, y[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + z[4] = t4 + z[5] = t5 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for algorithm documentation + + var t0, t1, t2, t3, t4, t5 uint64 + var u0, u1, u2, u3, u4, u5 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, x[0]) + u1, t1 = bits.Mul64(v, x[1]) + u2, t2 = bits.Mul64(v, x[2]) + u3, t3 = bits.Mul64(v, x[3]) + u4, t4 = bits.Mul64(v, x[4]) + u5, t5 = bits.Mul64(v, x[5]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[4] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[5] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + u4, c1 = bits.Mul64(v, x[4]) + t4, c0 = bits.Add64(c1, t4, c0) + u5, c1 = bits.Mul64(v, x[5]) + t5, c0 = bits.Add64(c1, t5, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + t4, c0 = bits.Add64(u3, t4, c0) + t5, c0 = bits.Add64(u4, t5, c0) + c2, _ = bits.Add64(u5, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + t2, c0 = bits.Add64(t3, c1, c0) + u4, c1 = bits.Mul64(m, q4) + t3, c0 = bits.Add64(t4, c1, c0) + u5, c1 = bits.Mul64(m, q5) + + t4, c0 = bits.Add64(0, c1, c0) + u5, _ = bits.Add64(u5, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + t3, c0 = bits.Add64(u3, t3, c0) + t4, c0 = bits.Add64(u4, t4, c0) + c2, _ = bits.Add64(c2, 0, c0) + t4, c0 = bits.Add64(t5, t4, 0) + t5, _ = bits.Add64(u5, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + z[4] = t4 + z[5] = t5 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], b = bits.Sub64(z[3], q3, b) + z[4], b = bits.Sub64(z[4], q4, b) + z[5], _ = bits.Sub64(z[5], q5, b) + } + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/vector.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/vector.go new file mode 100644 index 00000000000..3fe11371029 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/vector.go @@ -0,0 +1,255 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "runtime" + "strings" + "sync" + "sync/atomic" + "unsafe" +) + +// Vector represents a slice of Element. +// +// It implements the following interfaces: +// - Stringer +// - io.WriterTo +// - io.ReaderFrom +// - encoding.BinaryMarshaler +// - encoding.BinaryUnmarshaler +// - sort.Interface +type Vector []Element + +// MarshalBinary implements encoding.BinaryMarshaler +func (vector *Vector) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + + if _, err = vector.WriteTo(&buf); err != nil { + return + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (vector *Vector) UnmarshalBinary(data []byte) error { + r := bytes.NewReader(data) + _, err := vector.ReadFrom(r) + return err +} + +// WriteTo implements io.WriterTo and writes a vector of big endian encoded Element. +// Length of the vector is encoded as a uint32 on the first 4 bytes. +func (vector *Vector) WriteTo(w io.Writer) (int64, error) { + // encode slice length + if err := binary.Write(w, binary.BigEndian, uint32(len(*vector))); err != nil { + return 0, err + } + + n := int64(4) + + var buf [Bytes]byte + for i := 0; i < len(*vector); i++ { + BigEndian.PutElement(&buf, (*vector)[i]) + m, err := w.Write(buf[:]) + n += int64(m) + if err != nil { + return n, err + } + } + return n, nil +} + +// AsyncReadFrom reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +// It consumes the needed bytes from the reader and returns the number of bytes read and an error if any. +// It also returns a channel that will be closed when the validation is done. +// The validation consist of checking that the elements are smaller than the modulus, and +// converting them to montgomery form. +func (vector *Vector) AsyncReadFrom(r io.Reader) (int64, error, chan error) { + chErr := make(chan error, 1) + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + close(chErr) + return int64(read), err, chErr + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + if sliceLen == 0 { + close(chErr) + return n, nil, chErr + } + + bSlice := unsafe.Slice((*byte)(unsafe.Pointer(&(*vector)[0])), sliceLen*Bytes) + read, err := io.ReadFull(r, bSlice) + n += int64(read) + if err != nil { + close(chErr) + return n, err, chErr + } + + go func() { + var cptErrors uint64 + // process the elements in parallel + execute(int(sliceLen), func(start, end int) { + + var z Element + for i := start; i < end; i++ { + // we have to set vector[i] + bstart := i * Bytes + bend := bstart + Bytes + b := bSlice[bstart:bend] + z[0] = binary.BigEndian.Uint64(b[40:48]) + z[1] = binary.BigEndian.Uint64(b[32:40]) + z[2] = binary.BigEndian.Uint64(b[24:32]) + z[3] = binary.BigEndian.Uint64(b[16:24]) + z[4] = binary.BigEndian.Uint64(b[8:16]) + z[5] = binary.BigEndian.Uint64(b[0:8]) + + if !z.smallerThanModulus() { + atomic.AddUint64(&cptErrors, 1) + return + } + z.toMont() + (*vector)[i] = z + } + }) + + if cptErrors > 0 { + chErr <- fmt.Errorf("async read: %d elements failed validation", cptErrors) + } + close(chErr) + }() + return n, nil, chErr +} + +// ReadFrom implements io.ReaderFrom and reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +func (vector *Vector) ReadFrom(r io.Reader) (int64, error) { + + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + return int64(read), err + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + + for i := 0; i < int(sliceLen); i++ { + read, err := io.ReadFull(r, buf[:]) + n += int64(read) + if err != nil { + return n, err + } + (*vector)[i], err = BigEndian.Element(&buf) + if err != nil { + return n, err + } + } + + return n, nil +} + +// String implements fmt.Stringer interface +func (vector Vector) String() string { + var sbb strings.Builder + sbb.WriteByte('[') + for i := 0; i < len(vector); i++ { + sbb.WriteString(vector[i].String()) + if i != len(vector)-1 { + sbb.WriteByte(',') + } + } + sbb.WriteByte(']') + return sbb.String() +} + +// Len is the number of elements in the collection. +func (vector Vector) Len() int { + return len(vector) +} + +// Less reports whether the element with +// index i should sort before the element with index j. +func (vector Vector) Less(i, j int) bool { + return vector[i].Cmp(&vector[j]) == -1 +} + +// Swap swaps the elements with indexes i and j. +func (vector Vector) Swap(i, j int) { + vector[i], vector[j] = vector[j], vector[i] +} + +// TODO @gbotrel make a public package out of that. +// execute executes the work function in parallel. +// this is copy paste from internal/parallel/parallel.go +// as we don't want to generate code importing internal/ +func execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + if nbTasks < 1 { + nbTasks = 1 + } else if nbTasks > 512 { + nbTasks = 512 + } + } + + if nbTasks == 1 { + // no go routines + work(0, nbIterations) + return + } + + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/arith.go new file mode 100644 index 00000000000..7cfd55da199 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/arith.go @@ -0,0 +1,73 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "math/bits" +) + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} +func max(a int, b int) int { + if a > b { + return a + } + return b +} + +func min(a int, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm.go new file mode 100644 index 00000000000..da061913ba7 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm.go @@ -0,0 +1,27 @@ +//go:build !noadx +// +build !noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import "golang.org/x/sys/cpu" + +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm_noadx.go new file mode 100644 index 00000000000..7f52ffa197b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/asm_noadx.go @@ -0,0 +1,28 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var ( + supportAdx = false + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/doc.go new file mode 100644 index 00000000000..71ea8a2dc97 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/doc.go @@ -0,0 +1,53 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +// Package fr contains field arithmetic operations for modulus = 0x73eda7...000001. +// +// The API is similar to math/big (big.Int), but the operations are significantly faster (up to 20x for the modular multiplication on amd64, see also https://hackmd.io/@gnark/modular_multiplication) +// +// The modulus is hardcoded in all the operations. +// +// Field elements are represented as an array, and assumed to be in Montgomery form in all methods: +// +// type Element [4]uint64 +// +// # Usage +// +// Example API signature: +// +// // Mul z = x * y (mod q) +// func (z *Element) Mul(x, y *Element) *Element +// +// and can be used like so: +// +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus q = +// +// q[base10] = 52435875175126190479447740508185965837690552500527637822603658699938581184513 +// q[base16] = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +package fr diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element.go new file mode 100644 index 00000000000..aa6c47cdd13 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element.go @@ -0,0 +1,1620 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "crypto/rand" + "encoding/binary" + "errors" + "io" + "math/big" + "math/bits" + "reflect" + "strconv" + "strings" + + "github.com/bits-and-blooms/bitset" + "github.com/consensys/gnark-crypto/field/hash" + "github.com/consensys/gnark-crypto/field/pool" +) + +// Element represents a field element stored on 4 words (uint64) +// +// Element are assumed to be in Montgomery form in all methods. +// +// Modulus q = +// +// q[base10] = 52435875175126190479447740508185965837690552500527637822603658699938581184513 +// q[base16] = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. +type Element [4]uint64 + +const ( + Limbs = 4 // number of 64 bits words needed to represent a Element + Bits = 255 // number of bits needed to represent a Element + Bytes = 32 // number of bytes needed to represent a Element +) + +// Field modulus q +const ( + q0 uint64 = 18446744069414584321 + q1 uint64 = 6034159408538082302 + q2 uint64 = 3691218898639771653 + q3 uint64 = 8353516859464449352 +) + +var qElement = Element{ + q0, + q1, + q2, + q3, +} + +var _modulus big.Int // q stored as big.Int + +// Modulus returns q as a big.Int +// +// q[base10] = 52435875175126190479447740508185965837690552500527637822603658699938581184513 +// q[base16] = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 +func Modulus() *big.Int { + return new(big.Int).Set(&_modulus) +} + +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 18446744069414584319 + +func init() { + _modulus.SetString("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16) +} + +// NewElement returns a new Element from a uint64 value +// +// it is equivalent to +// +// var v Element +// v.SetUint64(...) +func NewElement(v uint64) Element { + z := Element{v} + z.Mul(&z, &rSquare) + return z +} + +// SetUint64 sets z to v and returns z +func (z *Element) SetUint64(v uint64) *Element { + // sets z LSB to v (non-Montgomery form) and convert z to Montgomery form + *z = Element{v} + return z.Mul(z, &rSquare) // z.toMont() +} + +// SetInt64 sets z to v and returns z +func (z *Element) SetInt64(v int64) *Element { + + // absolute value of v + m := v >> 63 + z.SetUint64(uint64((v ^ m) - m)) + + if m != 0 { + // v is negative + z.Neg(z) + } + + return z +} + +// Set z = x and returns z +func (z *Element) Set(x *Element) *Element { + z[0] = x[0] + z[1] = x[1] + z[2] = x[2] + z[3] = x[3] + return z +} + +// SetInterface converts provided interface into Element +// returns an error if provided type is not supported +// supported types: +// +// Element +// *Element +// uint64 +// int +// string (see SetString for valid formats) +// *big.Int +// big.Int +// []byte +func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + if i1 == nil { + return nil, errors.New("can't set fr.Element with ") + } + + switch c1 := i1.(type) { + case Element: + return z.Set(&c1), nil + case *Element: + if c1 == nil { + return nil, errors.New("can't set fr.Element with ") + } + return z.Set(c1), nil + case uint8: + return z.SetUint64(uint64(c1)), nil + case uint16: + return z.SetUint64(uint64(c1)), nil + case uint32: + return z.SetUint64(uint64(c1)), nil + case uint: + return z.SetUint64(uint64(c1)), nil + case uint64: + return z.SetUint64(c1), nil + case int8: + return z.SetInt64(int64(c1)), nil + case int16: + return z.SetInt64(int64(c1)), nil + case int32: + return z.SetInt64(int64(c1)), nil + case int64: + return z.SetInt64(c1), nil + case int: + return z.SetInt64(int64(c1)), nil + case string: + return z.SetString(c1) + case *big.Int: + if c1 == nil { + return nil, errors.New("can't set fr.Element with ") + } + return z.SetBigInt(c1), nil + case big.Int: + return z.SetBigInt(&c1), nil + case []byte: + return z.SetBytes(c1), nil + default: + return nil, errors.New("can't set fr.Element from type " + reflect.TypeOf(i1).String()) + } +} + +// SetZero z = 0 +func (z *Element) SetZero() *Element { + z[0] = 0 + z[1] = 0 + z[2] = 0 + z[3] = 0 + return z +} + +// SetOne z = 1 (in Montgomery form) +func (z *Element) SetOne() *Element { + z[0] = 8589934590 + z[1] = 6378425256633387010 + z[2] = 11064306276430008309 + z[3] = 1739710354780652911 + return z +} + +// Div z = x*y⁻¹ (mod q) +func (z *Element) Div(x, y *Element) *Element { + var yInv Element + yInv.Inverse(y) + z.Mul(x, &yInv) + return z +} + +// Equal returns z == x; constant-time +func (z *Element) Equal(x *Element) bool { + return z.NotEqual(x) == 0 +} + +// NotEqual returns 0 if and only if z == x; constant-time +func (z *Element) NotEqual(x *Element) uint64 { + return (z[3] ^ x[3]) | (z[2] ^ x[2]) | (z[1] ^ x[1]) | (z[0] ^ x[0]) +} + +// IsZero returns z == 0 +func (z *Element) IsZero() bool { + return (z[3] | z[2] | z[1] | z[0]) == 0 +} + +// IsOne returns z == 1 +func (z *Element) IsOne() bool { + return ((z[3] ^ 1739710354780652911) | (z[2] ^ 11064306276430008309) | (z[1] ^ 6378425256633387010) | (z[0] ^ 8589934590)) == 0 +} + +// IsUint64 reports whether z can be represented as an uint64. +func (z *Element) IsUint64() bool { + zz := *z + zz.fromMont() + return zz.FitsOnOneWord() +} + +// Uint64 returns the uint64 representation of x. If x cannot be represented in a uint64, the result is undefined. +func (z *Element) Uint64() uint64 { + return z.Bits()[0] +} + +// FitsOnOneWord reports whether z words (except the least significant word) are 0 +// +// It is the responsibility of the caller to convert from Montgomery to Regular form if needed. +func (z *Element) FitsOnOneWord() bool { + return (z[3] | z[2] | z[1]) == 0 +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *Element) Cmp(x *Element) int { + _z := z.Bits() + _x := x.Bits() + if _z[3] > _x[3] { + return 1 + } else if _z[3] < _x[3] { + return -1 + } + if _z[2] > _x[2] { + return 1 + } else if _z[2] < _x[2] { + return -1 + } + if _z[1] > _x[1] { + return 1 + } else if _z[1] < _x[1] { + return -1 + } + if _z[0] > _x[0] { + return 1 + } else if _z[0] < _x[0] { + return -1 + } + return 0 +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *Element) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + // we check if the element is larger than (q-1) / 2 + // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 + + _z := z.Bits() + + var b uint64 + _, b = bits.Sub64(_z[0], 9223372034707292161, 0) + _, b = bits.Sub64(_z[1], 12240451741123816959, b) + _, b = bits.Sub64(_z[2], 1845609449319885826, b) + _, b = bits.Sub64(_z[3], 4176758429732224676, b) + + return b == 0 +} + +// SetRandom sets z to a uniform random value in [0, q). +// +// This might error only if reading from crypto/rand.Reader errors, +// in which case, value of z is undefined. +func (z *Element) SetRandom() (*Element, error) { + // this code is generated for all modulus + // and derived from go/src/crypto/rand/util.go + + // l is number of limbs * 8; the number of bytes needed to reconstruct 4 uint64 + const l = 32 + + // bitLen is the maximum bit length needed to encode a value < q. + const bitLen = 255 + + // k is the maximum byte length needed to encode a value < q. + const k = (bitLen + 7) / 8 + + // b is the number of bits in the most significant byte of q-1. + b := uint(bitLen % 8) + if b == 0 { + b = 8 + } + + var bytes [l]byte + + for { + // note that bytes[k:l] is always 0 + if _, err := io.ReadFull(rand.Reader, bytes[:k]); err != nil { + return nil, err + } + + // Clear unused bits in in the most significant byte to increase probability + // that the candidate is < q. + bytes[k-1] &= uint8(int(1<> 1 + z[0] = z[0]>>1 | z[1]<<63 + z[1] = z[1]>>1 | z[2]<<63 + z[2] = z[2]>>1 | z[3]<<63 + z[3] >>= 1 + +} + +// fromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func (z *Element) fromMont() *Element { + fromMont(z) + return z +} + +// Add z = x + y (mod q) +func (z *Element) Add(x, y *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], _ = bits.Add64(x[3], y[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Double z = x + x (mod q), aka Lsh 1 +func (z *Element) Double(x *Element) *Element { + + var carry uint64 + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], _ = bits.Add64(x[3], x[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Sub z = x - y (mod q) +func (z *Element) Sub(x, y *Element) *Element { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], q0, 0) + z[1], c = bits.Add64(z[1], q1, c) + z[2], c = bits.Add64(z[2], q2, c) + z[3], _ = bits.Add64(z[3], q3, c) + } + return z +} + +// Neg z = q - x +func (z *Element) Neg(x *Element) *Element { + if x.IsZero() { + z.SetZero() + return z + } + var borrow uint64 + z[0], borrow = bits.Sub64(q0, x[0], 0) + z[1], borrow = bits.Sub64(q1, x[1], borrow) + z[2], borrow = bits.Sub64(q2, x[2], borrow) + z[3], _ = bits.Sub64(q3, x[3], borrow) + return z +} + +// Select is a constant-time conditional move. +// If c=0, z = x0. Else z = x1 +func (z *Element) Select(c int, x0 *Element, x1 *Element) *Element { + cC := uint64((int64(c) | -int64(c)) >> 63) // "canonicized" into: 0 if c=0, -1 otherwise + z[0] = x0[0] ^ cC&(x0[0]^x1[0]) + z[1] = x0[1] ^ cC&(x0[1]^x1[1]) + z[2] = x0[2] ^ cC&(x0[2]^x1[2]) + z[3] = x0[3] ^ cC&(x0[3]^x1[3]) + return z +} + +// _mulGeneric is unoptimized textbook CIOS +// it is a fallback solution on x86 when ADX instruction set is not available +// and is used for testing purposes. +func _mulGeneric(z, x, y *Element) { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + + var t [5]uint64 + var D uint64 + var m, C uint64 + // ----------------------------------- + // First loop + + C, t[0] = bits.Mul64(y[0], x[0]) + C, t[1] = madd1(y[0], x[1], C) + C, t[2] = madd1(y[0], x[2], C) + C, t[3] = madd1(y[0], x[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[1], x[0], t[0]) + C, t[1] = madd2(y[1], x[1], t[1], C) + C, t[2] = madd2(y[1], x[2], t[2], C) + C, t[3] = madd2(y[1], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[2], x[0], t[0]) + C, t[1] = madd2(y[2], x[1], t[1], C) + C, t[2] = madd2(y[2], x[2], t[2], C) + C, t[3] = madd2(y[2], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[3], x[0], t[0]) + C, t[1] = madd2(y[3], x[1], t[1], C) + C, t[2] = madd2(y[3], x[2], t[2], C) + C, t[3] = madd2(y[3], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + + if t[4] != 0 { + // we need to reduce, we have a result on 5 words + var b uint64 + z[0], b = bits.Sub64(t[0], q0, 0) + z[1], b = bits.Sub64(t[1], q1, b) + z[2], b = bits.Sub64(t[2], q2, b) + z[3], _ = bits.Sub64(t[3], q3, b) + return + } + + // copy t into z + z[0] = t[0] + z[1] = t[1] + z[2] = t[2] + z[3] = t[3] + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } +} + +func _fromMontGeneric(z *Element) { + // the following lines implement z = z * 1 + // with a modified CIOS montgomery multiplication + // see Mul for algorithm documentation + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + { + // m = z[0]n'[0] mod W + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) + z[3] = C + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } +} + +func _reduceGeneric(z *Element) { + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } +} + +// BatchInvert returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +func BatchInvert(a []Element) []Element { + res := make([]Element, len(a)) + if len(a) == 0 { + return res + } + + zeroes := bitset.New(uint(len(a))) + accumulator := One() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes.Set(uint(i)) + continue + } + res[i] = accumulator + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes.Test(uint(i)) { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func _butterflyGeneric(a, b *Element) { + t := *a + a.Add(a, b) + b.Sub(&t, b) +} + +// BitLen returns the minimum number of bits needed to represent z +// returns 0 if z == 0 +func (z *Element) BitLen() int { + if z[3] != 0 { + return 192 + bits.Len64(z[3]) + } + if z[2] != 0 { + return 128 + bits.Len64(z[2]) + } + if z[1] != 0 { + return 64 + bits.Len64(z[1]) + } + return bits.Len64(z[0]) +} + +// Hash msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func Hash(msg, dst []byte, count int) ([]Element, error) { + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + const Bytes = 1 + (Bits-1)/8 + const L = 16 + Bytes + + lenInBytes := count * L + pseudoRandomBytes, err := hash.ExpandMsgXmd(msg, dst, lenInBytes) + if err != nil { + return nil, err + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + res := make([]Element, count) + for i := 0; i < count; i++ { + vv.SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + res[i].SetBigInt(vv) + } + + // release object into pool + pool.BigInt.Put(vv) + + return res, nil +} + +// Exp z = xᵏ (mod q) +func (z *Element) Exp(x Element, k *big.Int) *Element { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q) == (x⁻¹)ᵏ (mod q) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = pool.BigInt.Get() + defer pool.BigInt.Put(e) + e.Neg(k) + } + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// rSquare where r is the Montgommery constant +// see section 2.3.2 of Tolga Acar's thesis +// https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf +var rSquare = Element{ + 14526898881837571181, + 3129137299524312099, + 419701826671360399, + 524908885293268753, +} + +// toMont converts z to Montgomery form +// sets and returns z = z * r² +func (z *Element) toMont() *Element { + return z.Mul(z, &rSquare) +} + +// String returns the decimal representation of z as generated by +// z.Text(10). +func (z *Element) String() string { + return z.Text(10) +} + +// toBigInt returns z as a big.Int in Montgomery form +func (z *Element) toBigInt(res *big.Int) *big.Int { + var b [Bytes]byte + binary.BigEndian.PutUint64(b[24:32], z[0]) + binary.BigEndian.PutUint64(b[16:24], z[1]) + binary.BigEndian.PutUint64(b[8:16], z[2]) + binary.BigEndian.PutUint64(b[0:8], z[3]) + + return res.SetBytes(b[:]) +} + +// Text returns the string representation of z in the given base. +// Base must be between 2 and 36, inclusive. The result uses the +// lower-case letters 'a' to 'z' for digit values 10 to 35. +// No prefix (such as "0x") is added to the string. If z is a nil +// pointer it returns "". +// If base == 10 and -z fits in a uint16 prefix "-" is added to the string. +func (z *Element) Text(base int) string { + if base < 2 || base > 36 { + panic("invalid base") + } + if z == nil { + return "" + } + + const maxUint16 = 65535 + if base == 10 { + var zzNeg Element + zzNeg.Neg(z) + zzNeg.fromMont() + if zzNeg.FitsOnOneWord() && zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { + return "-" + strconv.FormatUint(zzNeg[0], base) + } + } + zz := *z + zz.fromMont() + if zz.FitsOnOneWord() { + return strconv.FormatUint(zz[0], base) + } + vv := pool.BigInt.Get() + r := zz.toBigInt(vv).Text(base) + pool.BigInt.Put(vv) + return r +} + +// BigInt sets and return z as a *big.Int +func (z *Element) BigInt(res *big.Int) *big.Int { + _z := *z + _z.fromMont() + return _z.toBigInt(res) +} + +// ToBigIntRegular returns z as a big.Int in regular form +// +// Deprecated: use BigInt(*big.Int) instead +func (z Element) ToBigIntRegular(res *big.Int) *big.Int { + z.fromMont() + return z.toBigInt(res) +} + +// Bits provides access to z by returning its value as a little-endian [4]uint64 array. +// Bits is intended to support implementation of missing low-level Element +// functionality outside this package; it should be avoided otherwise. +func (z *Element) Bits() [4]uint64 { + _z := *z + fromMont(&_z) + return _z +} + +// Bytes returns the value of z as a big-endian byte array +func (z *Element) Bytes() (res [Bytes]byte) { + BigEndian.PutElement(&res, *z) + return +} + +// Marshal returns the value of z as a big-endian byte slice +func (z *Element) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// Unmarshal is an alias for SetBytes, it sets z to the value of e. +func (z *Element) Unmarshal(e []byte) { + z.SetBytes(e) +} + +// SetBytes interprets e as the bytes of a big-endian unsigned integer, +// sets z to that value, and returns z. +func (z *Element) SetBytes(e []byte) *Element { + if len(e) == Bytes { + // fast path + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err == nil { + *z = v + return z + } + } + + // slow path. + // get a big int from our pool + vv := pool.BigInt.Get() + vv.SetBytes(e) + + // set big int + z.SetBigInt(vv) + + // put temporary object back in pool + pool.BigInt.Put(vv) + + return z +} + +// SetBytesCanonical interprets e as the bytes of a big-endian 32-byte integer. +// If e is not a 32-byte slice or encodes a value higher than q, +// SetBytesCanonical returns an error. +func (z *Element) SetBytesCanonical(e []byte) error { + if len(e) != Bytes { + return errors.New("invalid fr.Element encoding") + } + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err != nil { + return err + } + *z = v + return nil +} + +// SetBigInt sets z to v and returns z +func (z *Element) SetBigInt(v *big.Int) *Element { + z.SetZero() + + var zero big.Int + + // fast path + c := v.Cmp(&_modulus) + if c == 0 { + // v == 0 + return z + } else if c != 1 && v.Cmp(&zero) != -1 { + // 0 < v < q + return z.setBigInt(v) + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + // copy input + modular reduction + vv.Mod(v, &_modulus) + + // set big int byte value + z.setBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return z +} + +// setBigInt assumes 0 ⩽ v < q +func (z *Element) setBigInt(v *big.Int) *Element { + vBits := v.Bits() + + if bits.UintSize == 64 { + for i := 0; i < len(vBits); i++ { + z[i] = uint64(vBits[i]) + } + } else { + for i := 0; i < len(vBits); i++ { + if i%2 == 0 { + z[i/2] = uint64(vBits[i]) + } else { + z[i/2] |= uint64(vBits[i]) << 32 + } + } + } + + return z.toMont() +} + +// SetString creates a big.Int with number and calls SetBigInt on z +// +// The number prefix determines the actual base: A prefix of +// ”0b” or ”0B” selects base 2, ”0”, ”0o” or ”0O” selects base 8, +// and ”0x” or ”0X” selects base 16. Otherwise, the selected base is 10 +// and no prefix is accepted. +// +// For base 16, lower and upper case letters are considered the same: +// The letters 'a' to 'f' and 'A' to 'F' represent digit values 10 to 15. +// +// An underscore character ”_” may appear between a base +// prefix and an adjacent digit, and between successive digits; such +// underscores do not change the value of the number. +// Incorrect placement of underscores is reported as a panic if there +// are no other errors. +// +// If the number is invalid this method leaves z unchanged and returns nil, error. +func (z *Element) SetString(number string) (*Element, error) { + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(number, 0); !ok { + return nil, errors.New("Element.SetString failed -> can't parse number into a big.Int " + number) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + + return z, nil +} + +// MarshalJSON returns json encoding of z (z.Text(10)) +// If z == nil, returns null +func (z *Element) MarshalJSON() ([]byte, error) { + if z == nil { + return []byte("null"), nil + } + const maxSafeBound = 15 // we encode it as number if it's small + s := z.Text(10) + if len(s) <= maxSafeBound { + return []byte(s), nil + } + var sbb strings.Builder + sbb.WriteByte('"') + sbb.WriteString(s) + sbb.WriteByte('"') + return []byte(sbb.String()), nil +} + +// UnmarshalJSON accepts numbers and strings as input +// See Element.SetString for valid prefixes (0x, 0b, ...) +func (z *Element) UnmarshalJSON(data []byte) error { + s := string(data) + if len(s) > Bits*3 { + return errors.New("value too large (max = Element.Bits * 3)") + } + + // we accept numbers and strings, remove leading and trailing quotes if any + if len(s) > 0 && s[0] == '"' { + s = s[1:] + } + if len(s) > 0 && s[len(s)-1] == '"' { + s = s[:len(s)-1] + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + if _, ok := vv.SetString(s, 0); !ok { + return errors.New("can't parse into a big.Int: " + s) + } + + z.SetBigInt(vv) + + // release object into pool + pool.BigInt.Put(vv) + return nil +} + +// A ByteOrder specifies how to convert byte slices into a Element +type ByteOrder interface { + Element(*[Bytes]byte) (Element, error) + PutElement(*[Bytes]byte, Element) + String() string +} + +// BigEndian is the big-endian implementation of ByteOrder and AppendByteOrder. +var BigEndian bigEndian + +type bigEndian struct{} + +// Element interpret b is a big-endian 32-byte slice. +// If b encodes a value higher than q, Element returns error. +func (bigEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.BigEndian.Uint64((*b)[24:32]) + z[1] = binary.BigEndian.Uint64((*b)[16:24]) + z[2] = binary.BigEndian.Uint64((*b)[8:16]) + z[3] = binary.BigEndian.Uint64((*b)[0:8]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fr.Element encoding") + } + + z.toMont() + return z, nil +} + +func (bigEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.BigEndian.PutUint64((*b)[24:32], e[0]) + binary.BigEndian.PutUint64((*b)[16:24], e[1]) + binary.BigEndian.PutUint64((*b)[8:16], e[2]) + binary.BigEndian.PutUint64((*b)[0:8], e[3]) +} + +func (bigEndian) String() string { return "BigEndian" } + +// LittleEndian is the little-endian implementation of ByteOrder and AppendByteOrder. +var LittleEndian littleEndian + +type littleEndian struct{} + +func (littleEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.LittleEndian.Uint64((*b)[0:8]) + z[1] = binary.LittleEndian.Uint64((*b)[8:16]) + z[2] = binary.LittleEndian.Uint64((*b)[16:24]) + z[3] = binary.LittleEndian.Uint64((*b)[24:32]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fr.Element encoding") + } + + z.toMont() + return z, nil +} + +func (littleEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.LittleEndian.PutUint64((*b)[0:8], e[0]) + binary.LittleEndian.PutUint64((*b)[8:16], e[1]) + binary.LittleEndian.PutUint64((*b)[16:24], e[2]) + binary.LittleEndian.PutUint64((*b)[24:32], e[3]) +} + +func (littleEndian) String() string { return "LittleEndian" } + +// Legendre returns the Legendre symbol of z (either +1, -1, or 0.) +func (z *Element) Legendre() int { + var l Element + // z^((q-1)/2) + l.expByLegendreExp(*z) + + if l.IsZero() { + return 0 + } + + // if l == 1 + if l.IsOne() { + return 1 + } + return -1 +} + +// Sqrt z = √x (mod q) +// if the square root doesn't exist (x is not a square mod q) +// Sqrt leaves z unchanged and returns nil +func (z *Element) Sqrt(x *Element) *Element { + // q ≡ 1 (mod 4) + // see modSqrtTonelliShanks in math/big/int.go + // using https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + + var y, b, t, w Element + // w = x^((s-1)/2)) + w.expBySqrtExp(*x) + + // y = x^((s+1)/2)) = w * x + y.Mul(x, &w) + + // b = xˢ = w * w * x = y * x + b.Mul(&w, &y) + + // g = nonResidue ^ s + var g = Element{ + 11289237133041595516, + 2081200955273736677, + 967625415375836421, + 4543825880697944938, + } + r := uint64(32) + + // compute legendre symbol + // t = x^((q-1)/2) = r-1 squaring of xˢ + t = b + for i := uint64(0); i < r-1; i++ { + t.Square(&t) + } + if t.IsZero() { + return z.SetZero() + } + if !t.IsOne() { + // t != 1, we don't have a square root + return nil + } + for { + var m uint64 + t = b + + // for t != 1 + for !t.IsOne() { + t.Square(&t) + m++ + } + + if m == 0 { + return z.Set(&y) + } + // t = g^(2^(r-m-1)) (mod q) + ge := int(r - m - 1) + t = g + for ge > 0 { + t.Square(&t) + ge-- + } + + g.Square(&t) + y.Mul(&y, &t) + b.Mul(&b, &g) + r = m + } +} + +const ( + k = 32 // word size / 2 + signBitSelector = uint64(1) << 63 + approxLowBitsN = k - 1 + approxHighBitsN = k + 1 +) + +const ( + inversionCorrectionFactorWord0 = 10120633560485349752 + inversionCorrectionFactorWord1 = 6708885176490223342 + inversionCorrectionFactorWord2 = 15589610060228208133 + inversionCorrectionFactorWord3 = 1857276366933877101 + invIterationsN = 18 +) + +// Inverse z = x⁻¹ (mod q) +// +// if x == 0, sets and returns z = x +func (z *Element) Inverse(x *Element) *Element { + // Implements "Optimized Binary GCD for Modular Inversion" + // https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf + + a := *x + b := Element{ + q0, + q1, + q2, + q3, + } // b := q + + u := Element{1} + + // Update factors: we get [u; v] ← [f₀ g₀; f₁ g₁] [u; v] + // cᵢ = fᵢ + 2³¹ - 1 + 2³² * (gᵢ + 2³¹ - 1) + var c0, c1 int64 + + // Saved update factors to reduce the number of field multiplications + var pf0, pf1, pg0, pg1 int64 + + var i uint + + var v, s Element + + // Since u,v are updated every other iteration, we must make sure we terminate after evenly many iterations + // This also lets us get away with half as many updates to u,v + // To make this constant-time-ish, replace the condition with i < invIterationsN + for i = 0; i&1 == 1 || !a.IsZero(); i++ { + n := max(a.BitLen(), b.BitLen()) + aApprox, bApprox := approximate(&a, n), approximate(&b, n) + + // f₀, g₀, f₁, g₁ = 1, 0, 0, 1 + c0, c1 = updateFactorIdentityMatrixRow0, updateFactorIdentityMatrixRow1 + + for j := 0; j < approxLowBitsN; j++ { + + // -2ʲ < f₀, f₁ ≤ 2ʲ + // |f₀| + |f₁| < 2ʲ⁺¹ + + if aApprox&1 == 0 { + aApprox /= 2 + } else { + s, borrow := bits.Sub64(aApprox, bApprox, 0) + if borrow == 1 { + s = bApprox - aApprox + bApprox = aApprox + c0, c1 = c1, c0 + // invariants unchanged + } + + aApprox = s / 2 + c0 = c0 - c1 + + // Now |f₀| < 2ʲ⁺¹ ≤ 2ʲ⁺¹ (only the weaker inequality is needed, strictly speaking) + // Started with f₀ > -2ʲ and f₁ ≤ 2ʲ, so f₀ - f₁ > -2ʲ⁺¹ + // Invariants unchanged for f₁ + } + + c1 *= 2 + // -2ʲ⁺¹ < f₁ ≤ 2ʲ⁺¹ + // So now |f₀| + |f₁| < 2ʲ⁺² + } + + s = a + + var g0 int64 + // from this point on c0 aliases for f0 + c0, g0 = updateFactorsDecompose(c0) + aHi := a.linearCombNonModular(&s, c0, &b, g0) + if aHi&signBitSelector != 0 { + // if aHi < 0 + c0, g0 = -c0, -g0 + aHi = negL(&a, aHi) + } + // right-shift a by k-1 bits + a[0] = (a[0] >> approxLowBitsN) | ((a[1]) << approxHighBitsN) + a[1] = (a[1] >> approxLowBitsN) | ((a[2]) << approxHighBitsN) + a[2] = (a[2] >> approxLowBitsN) | ((a[3]) << approxHighBitsN) + a[3] = (a[3] >> approxLowBitsN) | (aHi << approxHighBitsN) + + var f1 int64 + // from this point on c1 aliases for g0 + f1, c1 = updateFactorsDecompose(c1) + bHi := b.linearCombNonModular(&s, f1, &b, c1) + if bHi&signBitSelector != 0 { + // if bHi < 0 + f1, c1 = -f1, -c1 + bHi = negL(&b, bHi) + } + // right-shift b by k-1 bits + b[0] = (b[0] >> approxLowBitsN) | ((b[1]) << approxHighBitsN) + b[1] = (b[1] >> approxLowBitsN) | ((b[2]) << approxHighBitsN) + b[2] = (b[2] >> approxLowBitsN) | ((b[3]) << approxHighBitsN) + b[3] = (b[3] >> approxLowBitsN) | (bHi << approxHighBitsN) + + if i&1 == 1 { + // Combine current update factors with previously stored ones + // [F₀, G₀; F₁, G₁] ← [f₀, g₀; f₁, g₁] [pf₀, pg₀; pf₁, pg₁], with capital letters denoting new combined values + // We get |F₀| = | f₀pf₀ + g₀pf₁ | ≤ |f₀pf₀| + |g₀pf₁| = |f₀| |pf₀| + |g₀| |pf₁| ≤ 2ᵏ⁻¹|pf₀| + 2ᵏ⁻¹|pf₁| + // = 2ᵏ⁻¹ (|pf₀| + |pf₁|) < 2ᵏ⁻¹ 2ᵏ = 2²ᵏ⁻¹ + // So |F₀| < 2²ᵏ⁻¹ meaning it fits in a 2k-bit signed register + + // c₀ aliases f₀, c₁ aliases g₁ + c0, g0, f1, c1 = c0*pf0+g0*pf1, + c0*pg0+g0*pg1, + f1*pf0+c1*pf1, + f1*pg0+c1*pg1 + + s = u + + // 0 ≤ u, v < 2²⁵⁵ + // |F₀|, |G₀| < 2⁶³ + u.linearComb(&u, c0, &v, g0) + // |F₁|, |G₁| < 2⁶³ + v.linearComb(&s, f1, &v, c1) + + } else { + // Save update factors + pf0, pg0, pf1, pg1 = c0, g0, f1, c1 + } + } + + // For every iteration that we miss, v is not being multiplied by 2ᵏ⁻² + const pSq uint64 = 1 << (2 * (k - 1)) + a = Element{pSq} + // If the function is constant-time ish, this loop will not run (no need to take it out explicitly) + for ; i < invIterationsN; i += 2 { + // could optimize further with mul by word routine or by pre-computing a table since with k=26, + // we would multiply by pSq up to 13times; + // on x86, the assembly routine outperforms generic code for mul by word + // on arm64, we may loose up to ~5% for 6 limbs + v.Mul(&v, &a) + } + + u.Set(x) // for correctness check + + z.Mul(&v, &Element{ + inversionCorrectionFactorWord0, + inversionCorrectionFactorWord1, + inversionCorrectionFactorWord2, + inversionCorrectionFactorWord3, + }) + + // correctness check + v.Mul(&u, z) + if !v.IsOne() && !u.IsZero() { + return z.inverseExp(u) + } + + return z +} + +// inverseExp computes z = x⁻¹ (mod q) = x**(q-2) (mod q) +func (z *Element) inverseExp(x Element) *Element { + // e == q-2 + e := Modulus() + e.Sub(e, big.NewInt(2)) + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +// approximate a big number x into a single 64 bit word using its uppermost and lowermost bits +// if x fits in a word as is, no approximation necessary +func approximate(x *Element, nBits int) uint64 { + + if nBits <= 64 { + return x[0] + } + + const mask = (uint64(1) << (k - 1)) - 1 // k-1 ones + lo := mask & x[0] + + hiWordIndex := (nBits - 1) / 64 + + hiWordBitsAvailable := nBits - hiWordIndex*64 + hiWordBitsUsed := min(hiWordBitsAvailable, approxHighBitsN) + + mask_ := uint64(^((1 << (hiWordBitsAvailable - hiWordBitsUsed)) - 1)) + hi := (x[hiWordIndex] & mask_) << (64 - hiWordBitsAvailable) + + mask_ = ^(1<<(approxLowBitsN+hiWordBitsUsed) - 1) + mid := (mask_ & x[hiWordIndex-1]) >> hiWordBitsUsed + + return lo | mid | hi +} + +// linearComb z = xC * x + yC * y; +// 0 ≤ x, y < 2²⁵⁵ +// |xC|, |yC| < 2⁶³ +func (z *Element) linearComb(x *Element, xC int64, y *Element, yC int64) { + // | (hi, z) | < 2 * 2⁶³ * 2²⁵⁵ = 2³¹⁹ + // therefore | hi | < 2⁶³ ≤ 2⁶³ + hi := z.linearCombNonModular(x, xC, y, yC) + z.montReduceSigned(z, hi) +} + +// montReduceSigned z = (xHi * r + x) * r⁻¹ using the SOS algorithm +// Requires |xHi| < 2⁶³. Most significant bit of xHi is the sign bit. +func (z *Element) montReduceSigned(x *Element, xHi uint64) { + const signBitRemover = ^signBitSelector + mustNeg := xHi&signBitSelector != 0 + // the SOS implementation requires that most significant bit is 0 + // Let X be xHi*r + x + // If X is negative we would have initially stored it as 2⁶⁴ r + X (à la 2's complement) + xHi &= signBitRemover + // with this a negative X is now represented as 2⁶³ r + X + + var t [2*Limbs - 1]uint64 + var C uint64 + + m := x[0] * qInvNeg + + C = madd0(m, q0, x[0]) + C, t[1] = madd2(m, q1, x[1], C) + C, t[2] = madd2(m, q2, x[2], C) + C, t[3] = madd2(m, q3, x[3], C) + + // m * qElement[3] ≤ (2⁶⁴ - 1) * (2⁶³ - 1) = 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + // x[3] + C ≤ 2*(2⁶⁴ - 1) = 2⁶⁵ - 2 + // On LHS, (C, t[3]) ≤ 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + 2⁶⁵ - 2 = 2¹²⁷ + 2⁶³ - 1 + // So on LHS, C ≤ 2⁶³ + t[4] = xHi + C + // xHi + C < 2⁶³ + 2⁶³ = 2⁶⁴ + + // + { + const i = 1 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + + t[i+Limbs] += C + } + { + const i = 2 + m = t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) + + t[i+Limbs] += C + } + { + const i = 3 + m := t[i] * qInvNeg + + C = madd0(m, q0, t[i+0]) + C, z[0] = madd2(m, q1, t[i+1], C) + C, z[1] = madd2(m, q2, t[i+2], C) + z[3], z[2] = madd2(m, q3, t[i+3], C) + } + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + // + + if mustNeg { + // We have computed ( 2⁶³ r + X ) r⁻¹ = 2⁶³ + X r⁻¹ instead + var b uint64 + z[0], b = bits.Sub64(z[0], signBitSelector, 0) + z[1], b = bits.Sub64(z[1], 0, b) + z[2], b = bits.Sub64(z[2], 0, b) + z[3], b = bits.Sub64(z[3], 0, b) + + // Occurs iff x == 0 && xHi < 0, i.e. X = rX' for -2⁶³ ≤ X' < 0 + + if b != 0 { + // z[3] = -1 + // negative: add q + const neg1 = 0xFFFFFFFFFFFFFFFF + + var carry uint64 + + z[0], carry = bits.Add64(z[0], q0, 0) + z[1], carry = bits.Add64(z[1], q1, carry) + z[2], carry = bits.Add64(z[2], q2, carry) + z[3], _ = bits.Add64(neg1, q3, carry) + } + } +} + +const ( + updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) + updateFactorIdentityMatrixRow0 = 1 + updateFactorIdentityMatrixRow1 = 1 << 32 +) + +func updateFactorsDecompose(c int64) (int64, int64) { + c += updateFactorsConversionBias + const low32BitsFilter int64 = 0xFFFFFFFF + f := c&low32BitsFilter - 0x7FFFFFFF + g := c>>32&low32BitsFilter - 0x7FFFFFFF + return f, g +} + +// negL negates in place [x | xHi] and return the new most significant word xHi +func negL(x *Element, xHi uint64) uint64 { + var b uint64 + + x[0], b = bits.Sub64(0, x[0], 0) + x[1], b = bits.Sub64(0, x[1], b) + x[2], b = bits.Sub64(0, x[2], b) + x[3], b = bits.Sub64(0, x[3], b) + xHi, _ = bits.Sub64(0, xHi, b) + + return xHi +} + +// mulWNonModular multiplies by one word in non-montgomery, without reducing +func (z *Element) mulWNonModular(x *Element, y int64) uint64 { + + // w := abs(y) + m := y >> 63 + w := uint64((y ^ m) - m) + + var c uint64 + c, z[0] = bits.Mul64(x[0], w) + c, z[1] = madd1(x[1], w, c) + c, z[2] = madd1(x[2], w, c) + c, z[3] = madd1(x[3], w, c) + + if y < 0 { + c = negL(z, c) + } + + return c +} + +// linearCombNonModular computes a linear combination without modular reduction +func (z *Element) linearCombNonModular(x *Element, xC int64, y *Element, yC int64) uint64 { + var yTimes Element + + yHi := yTimes.mulWNonModular(y, yC) + xHi := z.mulWNonModular(x, xC) + + var carry uint64 + z[0], carry = bits.Add64(z[0], yTimes[0], 0) + z[1], carry = bits.Add64(z[1], yTimes[1], carry) + z[2], carry = bits.Add64(z[2], yTimes[2], carry) + z[3], carry = bits.Add64(z[3], yTimes[3], carry) + + yHi, _ = bits.Add64(xHi, yHi, carry) + + return yHi +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_exp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_exp.go new file mode 100644 index 00000000000..48073af8e64 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_exp.go @@ -0,0 +1,701 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +// expBySqrtExp is equivalent to z.Exp(x, 39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expBySqrtExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _100 = 2*_10 + // _110 = _10 + _100 + // _1100 = 2*_110 + // _10010 = _110 + _1100 + // _10011 = 1 + _10010 + // _10110 = _100 + _10010 + // _11000 = _10 + _10110 + // _11010 = _10 + _11000 + // _100010 = _1100 + _10110 + // _110101 = _10011 + _100010 + // _111011 = _110 + _110101 + // _1001011 = _10110 + _110101 + // _1001101 = _10 + _1001011 + // _1010101 = _11010 + _111011 + // _1100111 = _10010 + _1010101 + // _1101001 = _10 + _1100111 + // _10000011 = _11010 + _1101001 + // _10011001 = _10110 + _10000011 + // _10011101 = _100 + _10011001 + // _10111111 = _100010 + _10011101 + // _11010111 = _11000 + _10111111 + // _11011011 = _100 + _11010111 + // _11100111 = _1100 + _11011011 + // _11101111 = _11000 + _11010111 + // _11111111 = _11000 + _11100111 + // i54 = ((_11100111 << 8 + _11011011) << 9 + _10011101) << 9 + // i74 = ((_10011001 + i54) << 9 + _10011001) << 8 + _11010111 + // i101 = ((i74 << 6 + _110101) << 10 + _10000011) << 9 + // i120 = ((_1100111 + i101) << 8 + _111011) << 8 + 1 + // i161 = ((i120 << 14 + _1001101) << 10 + _111011) << 15 + // i182 = ((_1010101 + i161) << 10 + _11101111) << 8 + _1101001 + // i215 = ((i182 << 16 + _10111111) << 8 + _11111111) << 7 + // i235 = ((_1001011 + i215) << 9 + _11111111) << 8 + _10111111 + // i261 = ((i235 << 8 + _11111111) << 8 + _11111111) << 8 + // return 2*(_11111111 + i261) + 1 + // + // Operations: 217 squares 47 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + t12 = new(Element) + t13 = new(Element) + t14 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14 Element + // Step 1: t2 = x^0x2 + t2.Square(&x) + + // Step 2: t13 = x^0x4 + t13.Square(t2) + + // Step 3: t1 = x^0x6 + t1.Mul(t2, t13) + + // Step 4: t3 = x^0xc + t3.Square(t1) + + // Step 5: t7 = x^0x12 + t7.Mul(t1, t3) + + // Step 6: t4 = x^0x13 + t4.Mul(&x, t7) + + // Step 7: t10 = x^0x16 + t10.Mul(t13, t7) + + // Step 8: z = x^0x18 + z.Mul(t2, t10) + + // Step 9: t8 = x^0x1a + t8.Mul(t2, z) + + // Step 10: t0 = x^0x22 + t0.Mul(t3, t10) + + // Step 11: t9 = x^0x35 + t9.Mul(t4, t0) + + // Step 12: t5 = x^0x3b + t5.Mul(t1, t9) + + // Step 13: t1 = x^0x4b + t1.Mul(t10, t9) + + // Step 14: t6 = x^0x4d + t6.Mul(t2, t1) + + // Step 15: t4 = x^0x55 + t4.Mul(t8, t5) + + // Step 16: t7 = x^0x67 + t7.Mul(t7, t4) + + // Step 17: t2 = x^0x69 + t2.Mul(t2, t7) + + // Step 18: t8 = x^0x83 + t8.Mul(t8, t2) + + // Step 19: t11 = x^0x99 + t11.Mul(t10, t8) + + // Step 20: t12 = x^0x9d + t12.Mul(t13, t11) + + // Step 21: t0 = x^0xbf + t0.Mul(t0, t12) + + // Step 22: t10 = x^0xd7 + t10.Mul(z, t0) + + // Step 23: t13 = x^0xdb + t13.Mul(t13, t10) + + // Step 24: t14 = x^0xe7 + t14.Mul(t3, t13) + + // Step 25: t3 = x^0xef + t3.Mul(z, t10) + + // Step 26: z = x^0xff + z.Mul(z, t14) + + // Step 34: t14 = x^0xe700 + for s := 0; s < 8; s++ { + t14.Square(t14) + } + + // Step 35: t13 = x^0xe7db + t13.Mul(t13, t14) + + // Step 44: t13 = x^0x1cfb600 + for s := 0; s < 9; s++ { + t13.Square(t13) + } + + // Step 45: t12 = x^0x1cfb69d + t12.Mul(t12, t13) + + // Step 54: t12 = x^0x39f6d3a00 + for s := 0; s < 9; s++ { + t12.Square(t12) + } + + // Step 55: t12 = x^0x39f6d3a99 + t12.Mul(t11, t12) + + // Step 64: t12 = x^0x73eda753200 + for s := 0; s < 9; s++ { + t12.Square(t12) + } + + // Step 65: t11 = x^0x73eda753299 + t11.Mul(t11, t12) + + // Step 73: t11 = x^0x73eda75329900 + for s := 0; s < 8; s++ { + t11.Square(t11) + } + + // Step 74: t10 = x^0x73eda753299d7 + t10.Mul(t10, t11) + + // Step 80: t10 = x^0x1cfb69d4ca675c0 + for s := 0; s < 6; s++ { + t10.Square(t10) + } + + // Step 81: t9 = x^0x1cfb69d4ca675f5 + t9.Mul(t9, t10) + + // Step 91: t9 = x^0x73eda753299d7d400 + for s := 0; s < 10; s++ { + t9.Square(t9) + } + + // Step 92: t8 = x^0x73eda753299d7d483 + t8.Mul(t8, t9) + + // Step 101: t8 = x^0xe7db4ea6533afa90600 + for s := 0; s < 9; s++ { + t8.Square(t8) + } + + // Step 102: t7 = x^0xe7db4ea6533afa90667 + t7.Mul(t7, t8) + + // Step 110: t7 = x^0xe7db4ea6533afa9066700 + for s := 0; s < 8; s++ { + t7.Square(t7) + } + + // Step 111: t7 = x^0xe7db4ea6533afa906673b + t7.Mul(t5, t7) + + // Step 119: t7 = x^0xe7db4ea6533afa906673b00 + for s := 0; s < 8; s++ { + t7.Square(t7) + } + + // Step 120: t7 = x^0xe7db4ea6533afa906673b01 + t7.Mul(&x, t7) + + // Step 134: t7 = x^0x39f6d3a994cebea4199cec04000 + for s := 0; s < 14; s++ { + t7.Square(t7) + } + + // Step 135: t6 = x^0x39f6d3a994cebea4199cec0404d + t6.Mul(t6, t7) + + // Step 145: t6 = x^0xe7db4ea6533afa906673b01013400 + for s := 0; s < 10; s++ { + t6.Square(t6) + } + + // Step 146: t5 = x^0xe7db4ea6533afa906673b0101343b + t5.Mul(t5, t6) + + // Step 161: t5 = x^0x73eda753299d7d483339d80809a1d8000 + for s := 0; s < 15; s++ { + t5.Square(t5) + } + + // Step 162: t4 = x^0x73eda753299d7d483339d80809a1d8055 + t4.Mul(t4, t5) + + // Step 172: t4 = x^0x1cfb69d4ca675f520cce7602026876015400 + for s := 0; s < 10; s++ { + t4.Square(t4) + } + + // Step 173: t3 = x^0x1cfb69d4ca675f520cce76020268760154ef + t3.Mul(t3, t4) + + // Step 181: t3 = x^0x1cfb69d4ca675f520cce76020268760154ef00 + for s := 0; s < 8; s++ { + t3.Square(t3) + } + + // Step 182: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef69 + t2.Mul(t2, t3) + + // Step 198: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef690000 + for s := 0; s < 16; s++ { + t2.Square(t2) + } + + // Step 199: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bf + t2.Mul(t0, t2) + + // Step 207: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bf00 + for s := 0; s < 8; s++ { + t2.Square(t2) + } + + // Step 208: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff + t2.Mul(z, t2) + + // Step 215: t2 = x^0xe7db4ea6533afa906673b0101343b00aa77b4805fff80 + for s := 0; s < 7; s++ { + t2.Square(t2) + } + + // Step 216: t1 = x^0xe7db4ea6533afa906673b0101343b00aa77b4805fffcb + t1.Mul(t1, t2) + + // Step 225: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff9600 + for s := 0; s < 9; s++ { + t1.Square(t1) + } + + // Step 226: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ff + t1.Mul(z, t1) + + // Step 234: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ff00 + for s := 0; s < 8; s++ { + t1.Square(t1) + } + + // Step 235: t0 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbf + t0.Mul(t0, t1) + + // Step 243: t0 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbf00 + for s := 0; s < 8; s++ { + t0.Square(t0) + } + + // Step 244: t0 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfff + t0.Mul(z, t0) + + // Step 252: t0 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfff00 + for s := 0; s < 8; s++ { + t0.Square(t0) + } + + // Step 253: t0 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfffff + t0.Mul(z, t0) + + // Step 261: t0 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfffff00 + for s := 0; s < 8; s++ { + t0.Square(t0) + } + + // Step 262: z = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfffffff + z.Mul(z, t0) + + // Step 263: z = x^0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7ffffffe + z.Square(z) + + // Step 264: z = x^0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff + z.Mul(&x, z) + + return z +} + +// expByLegendreExp is equivalent to z.Exp(x, 39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff80000000) +// +// uses github.com/mmcloughlin/addchain v0.4.0 to generate a shorter addition chain +func (z *Element) expByLegendreExp(x Element) *Element { + // addition chain: + // + // _10 = 2*1 + // _11 = 1 + _10 + // _100 = 1 + _11 + // _110 = _10 + _100 + // _1100 = 2*_110 + // _10010 = _110 + _1100 + // _10011 = 1 + _10010 + // _10110 = _11 + _10011 + // _11000 = _10 + _10110 + // _11010 = _10 + _11000 + // _100010 = _1100 + _10110 + // _110101 = _10011 + _100010 + // _111011 = _110 + _110101 + // _1001011 = _10110 + _110101 + // _1001101 = _10 + _1001011 + // _1010101 = _11010 + _111011 + // _1100111 = _10010 + _1010101 + // _1101001 = _10 + _1100111 + // _10000011 = _11010 + _1101001 + // _10011001 = _10110 + _10000011 + // _10011101 = _100 + _10011001 + // _10111111 = _100010 + _10011101 + // _11010111 = _11000 + _10111111 + // _11011011 = _100 + _11010111 + // _11100111 = _1100 + _11011011 + // _11101111 = _11000 + _11010111 + // _11111111 = _11000 + _11100111 + // i55 = ((_11100111 << 8 + _11011011) << 9 + _10011101) << 9 + // i75 = ((_10011001 + i55) << 9 + _10011001) << 8 + _11010111 + // i102 = ((i75 << 6 + _110101) << 10 + _10000011) << 9 + // i121 = ((_1100111 + i102) << 8 + _111011) << 8 + 1 + // i162 = ((i121 << 14 + _1001101) << 10 + _111011) << 15 + // i183 = ((_1010101 + i162) << 10 + _11101111) << 8 + _1101001 + // i216 = ((i183 << 16 + _10111111) << 8 + _11111111) << 7 + // i236 = ((_1001011 + i216) << 9 + _11111111) << 8 + _10111111 + // i262 = ((i236 << 8 + _11111111) << 8 + _11111111) << 8 + // return ((_11111111 + i262) << 2 + _11) << 31 + // + // Operations: 248 squares 49 multiplies + + // Allocate Temporaries. + var ( + t0 = new(Element) + t1 = new(Element) + t2 = new(Element) + t3 = new(Element) + t4 = new(Element) + t5 = new(Element) + t6 = new(Element) + t7 = new(Element) + t8 = new(Element) + t9 = new(Element) + t10 = new(Element) + t11 = new(Element) + t12 = new(Element) + t13 = new(Element) + t14 = new(Element) + t15 = new(Element) + ) + + // var t0,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15 Element + // Step 1: t3 = x^0x2 + t3.Square(&x) + + // Step 2: z = x^0x3 + z.Mul(&x, t3) + + // Step 3: t14 = x^0x4 + t14.Mul(&x, z) + + // Step 4: t2 = x^0x6 + t2.Mul(t3, t14) + + // Step 5: t4 = x^0xc + t4.Square(t2) + + // Step 6: t8 = x^0x12 + t8.Mul(t2, t4) + + // Step 7: t5 = x^0x13 + t5.Mul(&x, t8) + + // Step 8: t11 = x^0x16 + t11.Mul(z, t5) + + // Step 9: t0 = x^0x18 + t0.Mul(t3, t11) + + // Step 10: t9 = x^0x1a + t9.Mul(t3, t0) + + // Step 11: t1 = x^0x22 + t1.Mul(t4, t11) + + // Step 12: t10 = x^0x35 + t10.Mul(t5, t1) + + // Step 13: t6 = x^0x3b + t6.Mul(t2, t10) + + // Step 14: t2 = x^0x4b + t2.Mul(t11, t10) + + // Step 15: t7 = x^0x4d + t7.Mul(t3, t2) + + // Step 16: t5 = x^0x55 + t5.Mul(t9, t6) + + // Step 17: t8 = x^0x67 + t8.Mul(t8, t5) + + // Step 18: t3 = x^0x69 + t3.Mul(t3, t8) + + // Step 19: t9 = x^0x83 + t9.Mul(t9, t3) + + // Step 20: t12 = x^0x99 + t12.Mul(t11, t9) + + // Step 21: t13 = x^0x9d + t13.Mul(t14, t12) + + // Step 22: t1 = x^0xbf + t1.Mul(t1, t13) + + // Step 23: t11 = x^0xd7 + t11.Mul(t0, t1) + + // Step 24: t14 = x^0xdb + t14.Mul(t14, t11) + + // Step 25: t15 = x^0xe7 + t15.Mul(t4, t14) + + // Step 26: t4 = x^0xef + t4.Mul(t0, t11) + + // Step 27: t0 = x^0xff + t0.Mul(t0, t15) + + // Step 35: t15 = x^0xe700 + for s := 0; s < 8; s++ { + t15.Square(t15) + } + + // Step 36: t14 = x^0xe7db + t14.Mul(t14, t15) + + // Step 45: t14 = x^0x1cfb600 + for s := 0; s < 9; s++ { + t14.Square(t14) + } + + // Step 46: t13 = x^0x1cfb69d + t13.Mul(t13, t14) + + // Step 55: t13 = x^0x39f6d3a00 + for s := 0; s < 9; s++ { + t13.Square(t13) + } + + // Step 56: t13 = x^0x39f6d3a99 + t13.Mul(t12, t13) + + // Step 65: t13 = x^0x73eda753200 + for s := 0; s < 9; s++ { + t13.Square(t13) + } + + // Step 66: t12 = x^0x73eda753299 + t12.Mul(t12, t13) + + // Step 74: t12 = x^0x73eda75329900 + for s := 0; s < 8; s++ { + t12.Square(t12) + } + + // Step 75: t11 = x^0x73eda753299d7 + t11.Mul(t11, t12) + + // Step 81: t11 = x^0x1cfb69d4ca675c0 + for s := 0; s < 6; s++ { + t11.Square(t11) + } + + // Step 82: t10 = x^0x1cfb69d4ca675f5 + t10.Mul(t10, t11) + + // Step 92: t10 = x^0x73eda753299d7d400 + for s := 0; s < 10; s++ { + t10.Square(t10) + } + + // Step 93: t9 = x^0x73eda753299d7d483 + t9.Mul(t9, t10) + + // Step 102: t9 = x^0xe7db4ea6533afa90600 + for s := 0; s < 9; s++ { + t9.Square(t9) + } + + // Step 103: t8 = x^0xe7db4ea6533afa90667 + t8.Mul(t8, t9) + + // Step 111: t8 = x^0xe7db4ea6533afa9066700 + for s := 0; s < 8; s++ { + t8.Square(t8) + } + + // Step 112: t8 = x^0xe7db4ea6533afa906673b + t8.Mul(t6, t8) + + // Step 120: t8 = x^0xe7db4ea6533afa906673b00 + for s := 0; s < 8; s++ { + t8.Square(t8) + } + + // Step 121: t8 = x^0xe7db4ea6533afa906673b01 + t8.Mul(&x, t8) + + // Step 135: t8 = x^0x39f6d3a994cebea4199cec04000 + for s := 0; s < 14; s++ { + t8.Square(t8) + } + + // Step 136: t7 = x^0x39f6d3a994cebea4199cec0404d + t7.Mul(t7, t8) + + // Step 146: t7 = x^0xe7db4ea6533afa906673b01013400 + for s := 0; s < 10; s++ { + t7.Square(t7) + } + + // Step 147: t6 = x^0xe7db4ea6533afa906673b0101343b + t6.Mul(t6, t7) + + // Step 162: t6 = x^0x73eda753299d7d483339d80809a1d8000 + for s := 0; s < 15; s++ { + t6.Square(t6) + } + + // Step 163: t5 = x^0x73eda753299d7d483339d80809a1d8055 + t5.Mul(t5, t6) + + // Step 173: t5 = x^0x1cfb69d4ca675f520cce7602026876015400 + for s := 0; s < 10; s++ { + t5.Square(t5) + } + + // Step 174: t4 = x^0x1cfb69d4ca675f520cce76020268760154ef + t4.Mul(t4, t5) + + // Step 182: t4 = x^0x1cfb69d4ca675f520cce76020268760154ef00 + for s := 0; s < 8; s++ { + t4.Square(t4) + } + + // Step 183: t3 = x^0x1cfb69d4ca675f520cce76020268760154ef69 + t3.Mul(t3, t4) + + // Step 199: t3 = x^0x1cfb69d4ca675f520cce76020268760154ef690000 + for s := 0; s < 16; s++ { + t3.Square(t3) + } + + // Step 200: t3 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bf + t3.Mul(t1, t3) + + // Step 208: t3 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bf00 + for s := 0; s < 8; s++ { + t3.Square(t3) + } + + // Step 209: t3 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff + t3.Mul(t0, t3) + + // Step 216: t3 = x^0xe7db4ea6533afa906673b0101343b00aa77b4805fff80 + for s := 0; s < 7; s++ { + t3.Square(t3) + } + + // Step 217: t2 = x^0xe7db4ea6533afa906673b0101343b00aa77b4805fffcb + t2.Mul(t2, t3) + + // Step 226: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff9600 + for s := 0; s < 9; s++ { + t2.Square(t2) + } + + // Step 227: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ff + t2.Mul(t0, t2) + + // Step 235: t2 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ff00 + for s := 0; s < 8; s++ { + t2.Square(t2) + } + + // Step 236: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbf + t1.Mul(t1, t2) + + // Step 244: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbf00 + for s := 0; s < 8; s++ { + t1.Square(t1) + } + + // Step 245: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfff + t1.Mul(t0, t1) + + // Step 253: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfff00 + for s := 0; s < 8; s++ { + t1.Square(t1) + } + + // Step 254: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfffff + t1.Mul(t0, t1) + + // Step 262: t1 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfffff00 + for s := 0; s < 8; s++ { + t1.Square(t1) + } + + // Step 263: t0 = x^0x1cfb69d4ca675f520cce76020268760154ef6900bfff96ffbfffffff + t0.Mul(t0, t1) + + // Step 265: t0 = x^0x73eda753299d7d483339d80809a1d80553bda402fffe5bfefffffffc + for s := 0; s < 2; s++ { + t0.Square(t0) + } + + // Step 266: z = x^0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff + z.Mul(z, t0) + + // Step 297: z = x^0x39f6d3a994cebea4199cec0404d0ec02a9ded2017fff2dff7fffffff80000000 + for s := 0; s < 31; s++ { + z.Square(z) + } + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_mul_adx_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_mul_amd64.s similarity index 92% rename from vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_mul_adx_amd64.s rename to vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_mul_amd64.s index bc0b747d255..ef89cc5dfd6 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_mul_adx_amd64.s +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_mul_amd64.s @@ -1,4 +1,4 @@ -// +build amd64_adx +// +build !purego // Copyright 2020 ConsenSys Software Inc. // @@ -18,14 +18,14 @@ #include "funcdata.h" // modulus q -DATA q<>+0(SB)/8, $0x43e1f593f0000001 -DATA q<>+8(SB)/8, $0x2833e84879b97091 -DATA q<>+16(SB)/8, $0xb85045b68181585d -DATA q<>+24(SB)/8, $0x30644e72e131a029 +DATA q<>+0(SB)/8, $0xffffffff00000001 +DATA q<>+8(SB)/8, $0x53bda402fffe5bfe +DATA q<>+16(SB)/8, $0x3339d80809a1d805 +DATA q<>+24(SB)/8, $0x73eda753299d7d48 GLOBL q<>(SB), (RODATA+NOPTR), $32 // qInv0 q'[0] -DATA qInv0<>(SB)/8, $0xc2e1f593efffffff +DATA qInv0<>(SB)/8, $0xfffffffeffffffff GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 #define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ @@ -43,10 +43,9 @@ GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 CMOVQCS rb3, ra3; \ // mul(res, x, y *Element) -TEXT ·mul(SB), NOSPLIT, $0-24 +TEXT ·mul(SB), $24-24 - // the algorithm is described here - // https://hackmd.io/@gnark/modular_multiplication + // the algorithm is described in the Element.Mul declaration (.go) // however, to benefit from the ADCX and ADOX carry chains // we split the inner loops in 2: // for i=0 to N-1 @@ -58,6 +57,9 @@ TEXT ·mul(SB), NOSPLIT, $0-24 // (C,t[j-1]) := t[j] + m*q[j] + C // t[N-1] = C + A + NO_LOCAL_POINTERS + CMPB ·supportAdx(SB), $1 + JNE l1 MOVQ x+8(FP), SI // x[0] -> DI @@ -320,7 +322,18 @@ TEXT ·mul(SB), NOSPLIT, $0-24 MOVQ BX, 24(AX) RET -TEXT ·fromMont(SB), NOSPLIT, $0-8 +l1: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·_mulGeneric(SB) + RET + +TEXT ·fromMont(SB), $8-8 + NO_LOCAL_POINTERS // the algorithm is described here // https://hackmd.io/@gnark/modular_multiplication @@ -333,6 +346,8 @@ TEXT ·fromMont(SB), NOSPLIT, $0-8 // for j=1 to N-1 // (C,t[j-1]) := t[j] + m*q[j] + C // t[N-1] = C + CMPB ·supportAdx(SB), $1 + JNE l2 MOVQ res+0(FP), DX MOVQ 0(DX), R14 MOVQ 8(DX), R13 @@ -464,3 +479,9 @@ TEXT ·fromMont(SB), NOSPLIT, $0-8 MOVQ CX, 16(AX) MOVQ BX, 24(AX) RET + +l2: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + CALL ·_fromMontGeneric(SB) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.go new file mode 100644 index 00000000000..e40a9caed55 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.go @@ -0,0 +1,107 @@ +//go:build !purego +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +//go:noescape +func MulBy3(x *Element) + +//go:noescape +func MulBy5(x *Element) + +//go:noescape +func MulBy13(x *Element) + +//go:noescape +func mul(res, x, y *Element) + +//go:noescape +func fromMont(res *Element) + +//go:noescape +func reduce(res *Element) + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +// +//go:noescape +func Butterfly(a, b *Element) + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + mul(z, x, y) + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for doc. + mul(z, x, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.s new file mode 100644 index 00000000000..dde38132813 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_amd64.s @@ -0,0 +1,230 @@ +// +build !purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0xffffffff00000001 +DATA q<>+8(SB)/8, $0x53bda402fffe5bfe +DATA q<>+16(SB)/8, $0x3339d80809a1d805 +DATA q<>+24(SB)/8, $0x73eda753299d7d48 +GLOBL q<>(SB), (RODATA+NOPTR), $32 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0xfffffffeffffffff +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + +TEXT ·reduce(SB), NOSPLIT, $0-8 + MOVQ res+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy3(x *Element) +TEXT ·MulBy3(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy5(x *Element) +TEXT ·MulBy5(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (R15,DI,R8,R9) + REDUCE(DX,CX,BX,SI,R15,DI,R8,R9) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// MulBy13(x *Element) +TEXT ·MulBy13(SB), NOSPLIT, $0-8 + MOVQ x+0(FP), AX + MOVQ 0(AX), DX + MOVQ 8(AX), CX + MOVQ 16(AX), BX + MOVQ 24(AX), SI + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (R11,R12,R13,R14) + REDUCE(DX,CX,BX,SI,R11,R12,R13,R14) + + MOVQ DX, R11 + MOVQ CX, R12 + MOVQ BX, R13 + MOVQ SI, R14 + ADDQ DX, DX + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ R11, DX + ADCQ R12, CX + ADCQ R13, BX + ADCQ R14, SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + ADDQ 0(AX), DX + ADCQ 8(AX), CX + ADCQ 16(AX), BX + ADCQ 24(AX), SI + + // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) + REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) + + MOVQ DX, 0(AX) + MOVQ CX, 8(AX) + MOVQ BX, 16(AX) + MOVQ SI, 24(AX) + RET + +// Butterfly(a, b *Element) sets a = a + b; b = a - b +TEXT ·Butterfly(SB), NOSPLIT, $0-16 + MOVQ a+0(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ CX, R8 + MOVQ BX, R9 + MOVQ SI, R10 + MOVQ DI, R11 + XORQ AX, AX + MOVQ b+8(FP), DX + ADDQ 0(DX), CX + ADCQ 8(DX), BX + ADCQ 16(DX), SI + ADCQ 24(DX), DI + SUBQ 0(DX), R8 + SBBQ 8(DX), R9 + SBBQ 16(DX), R10 + SBBQ 24(DX), R11 + MOVQ $0xffffffff00000001, R12 + MOVQ $0x53bda402fffe5bfe, R13 + MOVQ $0x3339d80809a1d805, R14 + MOVQ $0x73eda753299d7d48, R15 + CMOVQCC AX, R12 + CMOVQCC AX, R13 + CMOVQCC AX, R14 + CMOVQCC AX, R15 + ADDQ R12, R8 + ADCQ R13, R9 + ADCQ R14, R10 + ADCQ R15, R11 + MOVQ R8, 0(DX) + MOVQ R9, 8(DX) + MOVQ R10, 16(DX) + MOVQ R11, 24(DX) + + // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) + + MOVQ a+0(FP), AX + MOVQ CX, 0(AX) + MOVQ BX, 8(AX) + MOVQ SI, 16(AX) + MOVQ DI, 24(AX) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_purego.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_purego.go new file mode 100644 index 00000000000..258157ab792 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element_ops_purego.go @@ -0,0 +1,443 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import "math/bits" + +// MulBy3 x *= 3 (mod q) +func MulBy3(x *Element) { + _x := *x + x.Double(x).Add(x, &_x) +} + +// MulBy5 x *= 5 (mod q) +func MulBy5(x *Element) { + _x := *x + x.Double(x).Double(x).Add(x, &_x) +} + +// MulBy13 x *= 13 (mod q) +func MulBy13(x *Element) { + var y = Element{ + 120259084260, + 15510977298029211676, + 7326335280343703402, + 5909200893219589146, + } + x.Mul(x, &y) +} + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, y[0]) + u1, t1 = bits.Mul64(v, y[1]) + u2, t2 = bits.Mul64(v, y[2]) + u3, t3 = bits.Mul64(v, y[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for algorithm documentation + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, x[0]) + u1, t1 = bits.Mul64(v, x[1]) + u2, t2 = bits.Mul64(v, x[2]) + u3, t3 = bits.Mul64(v, x[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/vector.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/vector.go new file mode 100644 index 00000000000..00ad8a8986b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/vector.go @@ -0,0 +1,253 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "runtime" + "strings" + "sync" + "sync/atomic" + "unsafe" +) + +// Vector represents a slice of Element. +// +// It implements the following interfaces: +// - Stringer +// - io.WriterTo +// - io.ReaderFrom +// - encoding.BinaryMarshaler +// - encoding.BinaryUnmarshaler +// - sort.Interface +type Vector []Element + +// MarshalBinary implements encoding.BinaryMarshaler +func (vector *Vector) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + + if _, err = vector.WriteTo(&buf); err != nil { + return + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (vector *Vector) UnmarshalBinary(data []byte) error { + r := bytes.NewReader(data) + _, err := vector.ReadFrom(r) + return err +} + +// WriteTo implements io.WriterTo and writes a vector of big endian encoded Element. +// Length of the vector is encoded as a uint32 on the first 4 bytes. +func (vector *Vector) WriteTo(w io.Writer) (int64, error) { + // encode slice length + if err := binary.Write(w, binary.BigEndian, uint32(len(*vector))); err != nil { + return 0, err + } + + n := int64(4) + + var buf [Bytes]byte + for i := 0; i < len(*vector); i++ { + BigEndian.PutElement(&buf, (*vector)[i]) + m, err := w.Write(buf[:]) + n += int64(m) + if err != nil { + return n, err + } + } + return n, nil +} + +// AsyncReadFrom reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +// It consumes the needed bytes from the reader and returns the number of bytes read and an error if any. +// It also returns a channel that will be closed when the validation is done. +// The validation consist of checking that the elements are smaller than the modulus, and +// converting them to montgomery form. +func (vector *Vector) AsyncReadFrom(r io.Reader) (int64, error, chan error) { + chErr := make(chan error, 1) + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + close(chErr) + return int64(read), err, chErr + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + if sliceLen == 0 { + close(chErr) + return n, nil, chErr + } + + bSlice := unsafe.Slice((*byte)(unsafe.Pointer(&(*vector)[0])), sliceLen*Bytes) + read, err := io.ReadFull(r, bSlice) + n += int64(read) + if err != nil { + close(chErr) + return n, err, chErr + } + + go func() { + var cptErrors uint64 + // process the elements in parallel + execute(int(sliceLen), func(start, end int) { + + var z Element + for i := start; i < end; i++ { + // we have to set vector[i] + bstart := i * Bytes + bend := bstart + Bytes + b := bSlice[bstart:bend] + z[0] = binary.BigEndian.Uint64(b[24:32]) + z[1] = binary.BigEndian.Uint64(b[16:24]) + z[2] = binary.BigEndian.Uint64(b[8:16]) + z[3] = binary.BigEndian.Uint64(b[0:8]) + + if !z.smallerThanModulus() { + atomic.AddUint64(&cptErrors, 1) + return + } + z.toMont() + (*vector)[i] = z + } + }) + + if cptErrors > 0 { + chErr <- fmt.Errorf("async read: %d elements failed validation", cptErrors) + } + close(chErr) + }() + return n, nil, chErr +} + +// ReadFrom implements io.ReaderFrom and reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +func (vector *Vector) ReadFrom(r io.Reader) (int64, error) { + + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + return int64(read), err + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + + for i := 0; i < int(sliceLen); i++ { + read, err := io.ReadFull(r, buf[:]) + n += int64(read) + if err != nil { + return n, err + } + (*vector)[i], err = BigEndian.Element(&buf) + if err != nil { + return n, err + } + } + + return n, nil +} + +// String implements fmt.Stringer interface +func (vector Vector) String() string { + var sbb strings.Builder + sbb.WriteByte('[') + for i := 0; i < len(vector); i++ { + sbb.WriteString(vector[i].String()) + if i != len(vector)-1 { + sbb.WriteByte(',') + } + } + sbb.WriteByte(']') + return sbb.String() +} + +// Len is the number of elements in the collection. +func (vector Vector) Len() int { + return len(vector) +} + +// Less reports whether the element with +// index i should sort before the element with index j. +func (vector Vector) Less(i, j int) bool { + return vector[i].Cmp(&vector[j]) == -1 +} + +// Swap swaps the elements with indexes i and j. +func (vector Vector) Swap(i, j int) { + vector[i], vector[j] = vector[j], vector[i] +} + +// TODO @gbotrel make a public package out of that. +// execute executes the work function in parallel. +// this is copy paste from internal/parallel/parallel.go +// as we don't want to generate code importing internal/ +func execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + if nbTasks < 1 { + nbTasks = 1 + } else if nbTasks > 512 { + nbTasks = 512 + } + } + + if nbTasks == 1 { + // no go routines + work(0, nbIterations) + return + } + + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g1.go new file mode 100644 index 00000000000..c24a82cda65 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g1.go @@ -0,0 +1,1120 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/internal/parallel" + "math/big" + "runtime" +) + +// G1Affine point in affine coordinates +type G1Affine struct { + X, Y fp.Element +} + +// G1Jac is a point with fp.Element coordinates +type G1Jac struct { + X, Y, Z fp.Element +} + +// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +type g1JacExtended struct { + X, Y, ZZ, ZZZ fp.Element +} + +// ------------------------------------------------------------------------------------------------- +// Affine + +// Set sets p to the provided point +func (p *G1Affine) Set(a *G1Affine) *G1Affine { + p.X, p.Y = a.X, a.Y + return p +} + +// setInfinity sets p to O +func (p *G1Affine) setInfinity() *G1Affine { + p.X.SetZero() + p.Y.SetZero() + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { + var _p G1Jac + _p.FromAffine(a) + _p.mulGLV(&_p, s) + p.FromJacobian(&_p) + return p +} + +// ScalarMultiplicationAffine computes and returns p = a ⋅ s +// Takes an affine point and returns a Jacobian point (useful for KZG) +func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { + p.FromAffine(a) + p.mulGLV(p, s) + return p +} + +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + +// Add adds two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { + var p1, p2 G1Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.AddAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Double doubles a point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G1Affine) Double(a *G1Affine) *G1Affine { + var p1 G1Jac + p1.FromAffine(a) + p1.Double(&p1) + p.FromJacobian(&p1) + return p +} + +// Sub subs two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { + var p1, p2 G1Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.SubAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Equal tests if two points (in Affine coordinates) are equal +func (p *G1Affine) Equal(a *G1Affine) bool { + return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) +} + +// Neg computes -G +func (p *G1Affine) Neg(a *G1Affine) *G1Affine { + p.X = a.X + p.Y.Neg(&a.Y) + return p +} + +// FromJacobian rescales a point in Jacobian coord in z=1 plane +func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { + + var a, b fp.Element + + if p1.Z.IsZero() { + p.X.SetZero() + p.Y.SetZero() + return p + } + + a.Inverse(&p1.Z) + b.Square(&a) + p.X.Mul(&p1.X, &b) + p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a) + + return p +} + +// String returns the string representation of the point or "O" if it is infinity +func (p *G1Affine) String() string { + if p.IsInfinity() { + return "O" + } + return "E([" + p.X.String() + "," + p.Y.String() + "])" +} + +// IsInfinity checks if the point is infinity +// in affine, it's encoded as (0,0) +// (0,0) is never on the curve for j=0 curves +func (p *G1Affine) IsInfinity() bool { + return p.X.IsZero() && p.Y.IsZero() +} + +// IsOnCurve returns true if p in on the curve +func (p *G1Affine) IsOnCurve() bool { + var point G1Jac + point.FromAffine(p) + return point.IsOnCurve() // call this function to handle infinity point +} + +// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +func (p *G1Affine) IsInSubGroup() bool { + var _p G1Jac + _p.FromAffine(p) + return _p.IsInSubGroup() +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian + +// Set sets p to the provided point +func (p *G1Jac) Set(a *G1Jac) *G1Jac { + p.X, p.Y, p.Z = a.X, a.Y, a.Z + return p +} + +// Equal tests if two points (in Jacobian coordinates) are equal +func (p *G1Jac) Equal(a *G1Jac) bool { + // If one point is infinity, the other must also be infinity. + if p.Z.IsZero() { + return a.Z.IsZero() + } + // If the other point is infinity, return false since we can't + // the following checks would be incorrect. + if a.Z.IsZero() { + return false + } + + var pZSquare, aZSquare fp.Element + pZSquare.Square(&p.Z) + aZSquare.Square(&a.Z) + + var lhs, rhs fp.Element + lhs.Mul(&p.X, &aZSquare) + rhs.Mul(&a.X, &pZSquare) + if !lhs.Equal(&rhs) { + return false + } + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) + rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + + return lhs.Equal(&rhs) +} + +// Neg computes -G +func (p *G1Jac) Neg(a *G1Jac) *G1Jac { + *p = *a + p.Y.Neg(&a.Y) + return p +} + +// SubAssign subtracts two points on the curve +func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { + var tmp G1Jac + tmp.Set(a) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// AddAssign point addition in montgomery form +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl +func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { + + // p is infinity, return a + if p.Z.IsZero() { + p.Set(a) + return p + } + + // a is infinity, return p + if a.Z.IsZero() { + return p + } + + var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element + Z1Z1.Square(&a.Z) + Z2Z2.Square(&p.Z) + U1.Mul(&a.X, &Z2Z2) + U2.Mul(&p.X, &Z1Z1) + S1.Mul(&a.Y, &p.Z). + Mul(&S1, &Z2Z2) + S2.Mul(&p.Y, &a.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U1.Equal(&U2) && S1.Equal(&S2) { + return p.DoubleAssign() + } + + H.Sub(&U2, &U1) + I.Double(&H). + Square(&I) + J.Mul(&H, &I) + r.Sub(&S2, &S1).Double(&r) + V.Mul(&U1, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + S1.Mul(&S1, &J).Double(&S1) + p.Y.Sub(&p.Y, &S1) + p.Z.Add(&p.Z, &a.Z) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &Z2Z2). + Mul(&p.Z, &H) + + return p +} + +// AddMixed point addition +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl +func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.Z.IsZero() { + p.X = a.X + p.Y = a.Y + p.Z.SetOne() + return p + } + + var Z1Z1, U2, S2, H, HH, I, J, r, V fp.Element + Z1Z1.Square(&p.Z) + U2.Mul(&a.X, &Z1Z1) + S2.Mul(&a.Y, &p.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U2.Equal(&p.X) && S2.Equal(&p.Y) { + return p.DoubleAssign() + } + + H.Sub(&U2, &p.X) + HH.Square(&H) + I.Double(&HH).Double(&I) + J.Mul(&H, &I) + r.Sub(&S2, &p.Y).Double(&r) + V.Mul(&p.X, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + J.Mul(&J, &p.Y).Double(&J) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + p.Y.Sub(&p.Y, &J) + p.Z.Add(&p.Z, &H) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &HH) + + return p +} + +// Double doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G1Jac) Double(q *G1Jac) *G1Jac { + p.Set(q) + p.DoubleAssign() + return p +} + +// DoubleAssign doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G1Jac) DoubleAssign() *G1Jac { + + var XX, YY, YYYY, ZZ, S, M, T fp.Element + + XX.Square(&p.X) + YY.Square(&p.Y) + YYYY.Square(&YY) + ZZ.Square(&p.Z) + S.Add(&p.X, &YY) + S.Square(&S). + Sub(&S, &XX). + Sub(&S, &YYYY). + Double(&S) + M.Double(&XX).Add(&M, &XX) + p.Z.Add(&p.Z, &p.Y). + Square(&p.Z). + Sub(&p.Z, &YY). + Sub(&p.Z, &ZZ) + T.Square(&M) + p.X = T + T.Double(&S) + p.X.Sub(&p.X, &T) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M) + YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY) + p.Y.Sub(&p.Y, &YYYY) + + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { + return p.mulGLV(a, s) +} + +// String returns canonical representation of the point in affine coordinates +func (p *G1Jac) String() string { + _p := G1Affine{} + _p.FromJacobian(p) + return _p.String() +} + +// FromAffine sets p = Q, p in Jacobian, Q in affine +func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { + if Q.IsInfinity() { + p.Z.SetZero() + p.X.SetOne() + p.Y.SetOne() + return p + } + p.Z.SetOne() + p.X.Set(&Q.X) + p.Y.Set(&Q.Y) + return p +} + +// IsOnCurve returns true if p in on the curve +func (p *G1Jac) IsOnCurve() bool { + var left, right, tmp fp.Element + left.Square(&p.Y) + right.Square(&p.X).Mul(&right, &p.X) + tmp.Square(&p.Z). + Square(&tmp). + Mul(&tmp, &p.Z). + Mul(&tmp, &p.Z). + Mul(&tmp, &bCurveCoeff) + right.Add(&right, &tmp) + return left.Equal(&right) +} + +// IsInSubGroup returns true if p is on the r-torsion, false otherwise. +// Z[r,0]+Z[-lambdaG1Affine, 1] is the kernel +// of (u,v)->u+lambdaG1Affinev mod r. Expressing r, lambdaG1Affine as +// polynomials in x, a short vector of this Zmodule is +// 1, x². So we check that p+x²ϕ(p) +// is the infinity. +func (p *G1Jac) IsInSubGroup() bool { + + var res G1Jac + + res.phi(p). + ScalarMultiplication(&res, &xGen). + ScalarMultiplication(&res, &xGen). + AddAssign(p) + + return res.IsOnCurve() && res.Z.IsZero() + +} + +// mulWindowed computes a 2-bits windowed scalar multiplication +func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { + + var res G1Jac + var ops [3]G1Jac + + ops[0].Set(a) + if s.Sign() == -1 { + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) + ops[1].Double(&ops[0]) + ops[2].Set(&ops[0]).AddAssign(&ops[1]) + + b := s.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.DoubleAssign().DoubleAssign() + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.AddAssign(&ops[c-1]) + } + mask = mask >> 2 + } + } + p.Set(&res) + + return p + +} + +// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p +// where w is a third root of unity in 𝔽p +func (p *G1Jac) phi(a *G1Jac) *G1Jac { + p.Set(a) + p.X.Mul(&p.X, &thirdRootOneG1) + return p +} + +// mulGLV computes the scalar multiplication using a windowed-GLV method +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { + + var table [15]G1Jac + var res G1Jac + var k1, k2 fr.Element + + res.Set(&g1Infinity) + + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a + table[0].Set(a) + table[3].phi(a) + + // split the scalar, modifies ±a, ϕ(a) accordingly + k := ecc.SplitScalar(s, &glvBasis) + + if k[0].Sign() == -1 { + k[0].Neg(&k[0]) + table[0].Neg(&table[0]) + } + if k[1].Sign() == -1 { + k[1].Neg(&k[1]) + table[3].Neg(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max + // this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift + k1 = k1.SetBigInt(&k[0]).Bits() + k2 = k2.SetBigInt(&k[1]).Bits() + + // we don't target constant-timeness so we check first if we increase the bounds or not + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (k1[i] & mask) >> (62 - 2*j) + b2 := (k2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G1Affine) ClearCofactor(a *G1Affine) *G1Affine { + var _p G1Jac + _p.FromAffine(a) + _p.ClearCofactor(&_p) + p.FromJacobian(&_p) + return p +} + +// ClearCofactor maps a point in E(Fp) to E(Fp)[r] +func (p *G1Jac) ClearCofactor(a *G1Jac) *G1Jac { + // cf https://eprint.iacr.org/2019/403.pdf, 5 + var res G1Jac + res.ScalarMultiplication(a, &xGen).AddAssign(a) + p.Set(&res) + return p + +} + +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.Set(&g1Gen) + p2.FromAffine(a) + + var table [15]G1Jac + + var k1, k2 big.Int + if s1.Sign() == -1 { + k1.Neg(s1) + table[0].Neg(&p1) + } else { + k1.Set(s1) + table[0].Set(&p1) + } + if s2.Sign() == -1 { + k2.Neg(s2) + table[3].Neg(&p2) + } else { + k2.Set(s2) + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() + + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian extended + +// Set sets p to the provided point +func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ + return p +} + +// setInfinity sets p to O +func (p *g1JacExtended) setInfinity() *g1JacExtended { + p.X.SetOne() + p.Y.SetOne() + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p +} + +func (p *g1JacExtended) IsZero() bool { + return p.ZZ.IsZero() +} + +// fromJacExtended sets Q in affine coordinates +func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { + if Q.ZZ.IsZero() { + p.X = fp.Element{} + p.Y = fp.Element{} + return p + } + p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + return p +} + +// fromJacExtended sets Q in Jacobian coordinates +func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { + if Q.ZZ.IsZero() { + p.Set(&g1Infinity) + return p + } + p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) + p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) + p.Z.Set(&Q.ZZZ) + return p +} + +// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity +func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { + p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.Z = Q.ZZZ + return p +} + +// add point in Jacobian extended coordinates +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s +func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { + //if q is infinity return p + if q.ZZ.IsZero() { + return p + } + // p is infinity, return q + if p.ZZ.IsZero() { + p.Set(q) + return p + } + + var A, B, U1, U2, S1, S2 fp.Element + + // p2: q, p1: p + U2.Mul(&q.X, &p.ZZ) + U1.Mul(&p.X, &q.ZZ) + A.Sub(&U2, &U1) + S2.Mul(&q.Y, &p.ZZZ) + S1.Mul(&p.Y, &q.ZZZ) + B.Sub(&S2, &S1) + + if A.IsZero() { + if B.IsZero() { + return p.double(q) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var P, R, PP, PPP, Q, V fp.Element + P.Sub(&U2, &U1) + R.Sub(&S2, &S1) + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&U1, &PP) + V.Mul(&S1, &PPP) + + p.X.Square(&R). + Sub(&p.X, &PPP). + Sub(&p.X, &Q). + Sub(&p.X, &Q) + p.Y.Sub(&Q, &p.X). + Mul(&p.Y, &R). + Sub(&p.Y, &V) + p.ZZ.Mul(&p.ZZ, &q.ZZ). + Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &q.ZZZ). + Mul(&p.ZZZ, &PPP) + + return p +} + +// double point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +// since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well +func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { + var U, V, W, S, XX, M fp.Element + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + U.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S). + Sub(&p.X, &S) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &U) + p.ZZ.Mul(&V, &q.ZZ) + p.ZZZ.Mul(&W, &q.ZZZ) + + return p +} + +// subMixed same as addMixed, but will negate a.Y +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y.Neg(&a.Y) + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fp.Element + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleNegMixed(a) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// addMixed +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y = a.Y + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fp.Element + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleMixed(a) + + } + p.ZZ = fp.Element{} + p.ZZZ = fp.Element{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// doubleNegMixed same as double, but will negate q.Y +func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { + + var U, V, W, S, XX, M, S2, L fp.Element + + U.Double(&q.Y) + U.Neg(&U) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Add(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// doubleMixed point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { + + var U, V, W, S, XX, M, S2, L fp.Element + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) + zeroes := make([]bool, len(points)) + accumulator := fp.One() + + // batch invert all points[].Z coordinates with Montgomery batch inversion trick + // (stores points[].Z^-1 in result[i].X to avoid allocating a slice of fr.Elements) + for i := 0; i < len(points); i++ { + if points[i].Z.IsZero() { + zeroes[i] = true + continue + } + result[i].X = accumulator + accumulator.Mul(&accumulator, &points[i].Z) + } + + var accInverse fp.Element + accInverse.Inverse(&accumulator) + + for i := len(points) - 1; i >= 0; i-- { + if zeroes[i] { + // do nothing, (X=0, Y=0) is infinity point in affine + continue + } + result[i].X.Mul(&result[i].X, &accInverse) + accInverse.Mul(&accInverse, &points[i].Z) + } + + // batch convert to affine. + parallel.Execute(len(points), func(start, end int) { + for i := start; i < end; i++ { + if zeroes[i] { + // do nothing, (X=0, Y=0) is infinity point in affine + continue + } + var a, b fp.Element + a = result[i].X + b.Square(&a) + result[i].X.Mul(&points[i].X, &b) + result[i].Y.Mul(&points[i].Y, &b). + Mul(&result[i].Y, &a) + } + }) + + return result +} + +// BatchScalarMultiplicationG1 multiplies the same base by all scalars +// and return resulting points in affine coordinates +// uses a simple windowed-NAF like exponentiation algorithm +func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { + // approximate cost in group ops is + // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) + + nbPoints := uint64(len(scalars)) + min := ^uint64(0) + bestC := 0 + for c := 2; c <= 16; c++ { + cost := uint64(1 << (c - 1)) // pre compute the table + nbChunks := computeNbChunks(uint64(c)) + cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add + if cost < min { + min = cost + bestC = c + } + } + c := uint64(bestC) // window size + nbChunks := int(computeNbChunks(c)) + + // last window may be slightly larger than c; in which case we need to compute one + // extra element in the baseTable + maxC := lastC(c) + if c > maxC { + maxC = c + } + + // precompute all powers of base for our window + // note here that if performance is critical, we can implement as in the msmX methods + // this allocation to be on the stack + baseTable := make([]G1Jac, (1 << (maxC - 1))) + baseTable[0].FromAffine(base) + for i := 1; i < len(baseTable); i++ { + baseTable[i] = baseTable[i-1] + baseTable[i].AddMixed(base) + } + // convert our base exp table into affine to use AddMixed + baseTableAff := BatchJacobianToAffineG1(baseTable) + toReturn := make([]G1Jac, len(scalars)) + + // partition the scalars into digits + digits, _ := partitionScalars(scalars, c, runtime.NumCPU()) + + // for each digit, take value in the base table, double it c time, voilà. + parallel.Execute(len(scalars), func(start, end int) { + var p G1Jac + for i := start; i < end; i++ { + p.Set(&g1Infinity) + for chunk := nbChunks - 1; chunk >= 0; chunk-- { + if chunk != nbChunks-1 { + for j := uint64(0); j < c; j++ { + p.DoubleAssign() + } + } + offset := chunk * len(scalars) + digit := digits[i+offset] + + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + p.AddMixed(&baseTableAff[(digit>>1)-1]) + } else { + // sub + t := baseTableAff[digit>>1] + t.Neg(&t) + p.AddMixed(&t) + } + } + + // set our result point + toReturn[i] = p + + } + }) + toReturnAff := BatchJacobianToAffineG1(toReturn) + return toReturnAff +} + +// batch add affine coordinates +// using batch inversion +// special cases (doubling, infinity) must be filtered out before this call +func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { + var lambda, lambdain TC + + // add part + for j := 0; j < batchSize; j++ { + lambdain[j].Sub(&(*P)[j].X, &(*R)[j].X) + } + + // invert denominator using montgomery batch invert technique + { + var accumulator fp.Element + lambda[0].SetOne() + accumulator.Set(&lambdain[0]) + + for i := 1; i < batchSize; i++ { + lambda[i] = accumulator + accumulator.Mul(&accumulator, &lambdain[i]) + } + + accumulator.Inverse(&accumulator) + + for i := batchSize - 1; i > 0; i-- { + lambda[i].Mul(&lambda[i], &accumulator) + accumulator.Mul(&accumulator, &lambdain[i]) + } + lambda[0].Set(&accumulator) + } + + var d fp.Element + var rr G1Affine + + // add part + for j := 0; j < batchSize; j++ { + // computa lambda + d.Sub(&(*P)[j].Y, &(*R)[j].Y) + lambda[j].Mul(&lambda[j], &d) + + // compute X, Y + rr.X.Square(&lambda[j]) + rr.X.Sub(&rr.X, &(*R)[j].X) + rr.X.Sub(&rr.X, &(*P)[j].X) + d.Sub(&(*R)[j].X, &rr.X) + rr.Y.Mul(&lambda[j], &d) + rr.Y.Sub(&rr.Y, &(*R)[j].Y) + (*R)[j].Set(&rr) + } +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g2.go new file mode 100644 index 00000000000..cd32bfb46b0 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g2.go @@ -0,0 +1,1037 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" + "math/big" + "runtime" +) + +// G2Affine point in affine coordinates +type G2Affine struct { + X, Y fptower.E2 +} + +// G2Jac is a point with fptower.E2 coordinates +type G2Jac struct { + X, Y, Z fptower.E2 +} + +// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) +type g2JacExtended struct { + X, Y, ZZ, ZZZ fptower.E2 +} + +// g2Proj point in projective coordinates +type g2Proj struct { + x, y, z fptower.E2 +} + +// ------------------------------------------------------------------------------------------------- +// Affine + +// Set sets p to the provided point +func (p *G2Affine) Set(a *G2Affine) *G2Affine { + p.X, p.Y = a.X, a.Y + return p +} + +// setInfinity sets p to O +func (p *G2Affine) setInfinity() *G2Affine { + p.X.SetZero() + p.Y.SetZero() + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { + var _p G2Jac + _p.FromAffine(a) + _p.mulGLV(&_p, s) + p.FromJacobian(&_p) + return p +} + +// Add adds two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { + var p1, p2 G2Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.AddAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Double doubles a point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G2Affine) Double(a *G2Affine) *G2Affine { + var p1 G2Jac + p1.FromAffine(a) + p1.Double(&p1) + p.FromJacobian(&p1) + return p +} + +// Sub subs two point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { + var p1, p2 G2Jac + p1.FromAffine(a) + p2.FromAffine(b) + p1.SubAssign(&p2) + p.FromJacobian(&p1) + return p +} + +// Equal tests if two points (in Affine coordinates) are equal +func (p *G2Affine) Equal(a *G2Affine) bool { + return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) +} + +// Neg computes -G +func (p *G2Affine) Neg(a *G2Affine) *G2Affine { + p.X = a.X + p.Y.Neg(&a.Y) + return p +} + +// FromJacobian rescales a point in Jacobian coord in z=1 plane +func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { + + var a, b fptower.E2 + + if p1.Z.IsZero() { + p.X.SetZero() + p.Y.SetZero() + return p + } + + a.Inverse(&p1.Z) + b.Square(&a) + p.X.Mul(&p1.X, &b) + p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a) + + return p +} + +// String returns the string representation of the point or "O" if it is infinity +func (p *G2Affine) String() string { + if p.IsInfinity() { + return "O" + } + return "E([" + p.X.String() + "," + p.Y.String() + "])" +} + +// IsInfinity checks if the point is infinity +// in affine, it's encoded as (0,0) +// (0,0) is never on the curve for j=0 curves +func (p *G2Affine) IsInfinity() bool { + return p.X.IsZero() && p.Y.IsZero() +} + +// IsOnCurve returns true if p in on the curve +func (p *G2Affine) IsOnCurve() bool { + var point G2Jac + point.FromAffine(p) + return point.IsOnCurve() // call this function to handle infinity point +} + +// IsInSubGroup returns true if p is in the correct subgroup, false otherwise +func (p *G2Affine) IsInSubGroup() bool { + var _p G2Jac + _p.FromAffine(p) + return _p.IsInSubGroup() +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian + +// Set sets p to the provided point +func (p *G2Jac) Set(a *G2Jac) *G2Jac { + p.X, p.Y, p.Z = a.X, a.Y, a.Z + return p +} + +// Equal tests if two points (in Jacobian coordinates) are equal +func (p *G2Jac) Equal(a *G2Jac) bool { + // If one point is infinity, the other must also be infinity. + if p.Z.IsZero() { + return a.Z.IsZero() + } + // If the other point is infinity, return false since we can't + // the following checks would be incorrect. + if a.Z.IsZero() { + return false + } + + var pZSquare, aZSquare fptower.E2 + pZSquare.Square(&p.Z) + aZSquare.Square(&a.Z) + + var lhs, rhs fptower.E2 + lhs.Mul(&p.X, &aZSquare) + rhs.Mul(&a.X, &pZSquare) + if !lhs.Equal(&rhs) { + return false + } + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) + rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + + return lhs.Equal(&rhs) +} + +// Neg computes -G +func (p *G2Jac) Neg(a *G2Jac) *G2Jac { + *p = *a + p.Y.Neg(&a.Y) + return p +} + +// SubAssign subtracts two points on the curve +func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { + var tmp G2Jac + tmp.Set(a) + tmp.Y.Neg(&tmp.Y) + p.AddAssign(&tmp) + return p +} + +// AddAssign point addition in montgomery form +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl +func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { + + // p is infinity, return a + if p.Z.IsZero() { + p.Set(a) + return p + } + + // a is infinity, return p + if a.Z.IsZero() { + return p + } + + var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fptower.E2 + Z1Z1.Square(&a.Z) + Z2Z2.Square(&p.Z) + U1.Mul(&a.X, &Z2Z2) + U2.Mul(&p.X, &Z1Z1) + S1.Mul(&a.Y, &p.Z). + Mul(&S1, &Z2Z2) + S2.Mul(&p.Y, &a.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U1.Equal(&U2) && S1.Equal(&S2) { + return p.DoubleAssign() + } + + H.Sub(&U2, &U1) + I.Double(&H). + Square(&I) + J.Mul(&H, &I) + r.Sub(&S2, &S1).Double(&r) + V.Mul(&U1, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + S1.Mul(&S1, &J).Double(&S1) + p.Y.Sub(&p.Y, &S1) + p.Z.Add(&p.Z, &a.Z) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &Z2Z2). + Mul(&p.Z, &H) + + return p +} + +// AddMixed point addition +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl +func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.Z.IsZero() { + p.X = a.X + p.Y = a.Y + p.Z.SetOne() + return p + } + + var Z1Z1, U2, S2, H, HH, I, J, r, V fptower.E2 + Z1Z1.Square(&p.Z) + U2.Mul(&a.X, &Z1Z1) + S2.Mul(&a.Y, &p.Z). + Mul(&S2, &Z1Z1) + + // if p == a, we double instead + if U2.Equal(&p.X) && S2.Equal(&p.Y) { + return p.DoubleAssign() + } + + H.Sub(&U2, &p.X) + HH.Square(&H) + I.Double(&HH).Double(&I) + J.Mul(&H, &I) + r.Sub(&S2, &p.Y).Double(&r) + V.Mul(&p.X, &I) + p.X.Square(&r). + Sub(&p.X, &J). + Sub(&p.X, &V). + Sub(&p.X, &V) + J.Mul(&J, &p.Y).Double(&J) + p.Y.Sub(&V, &p.X). + Mul(&p.Y, &r) + p.Y.Sub(&p.Y, &J) + p.Z.Add(&p.Z, &H) + p.Z.Square(&p.Z). + Sub(&p.Z, &Z1Z1). + Sub(&p.Z, &HH) + + return p +} + +// Double doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G2Jac) Double(q *G2Jac) *G2Jac { + p.Set(q) + p.DoubleAssign() + return p +} + +// DoubleAssign doubles a point in Jacobian coordinates +// https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl +func (p *G2Jac) DoubleAssign() *G2Jac { + + var XX, YY, YYYY, ZZ, S, M, T fptower.E2 + + XX.Square(&p.X) + YY.Square(&p.Y) + YYYY.Square(&YY) + ZZ.Square(&p.Z) + S.Add(&p.X, &YY) + S.Square(&S). + Sub(&S, &XX). + Sub(&S, &YYYY). + Double(&S) + M.Double(&XX).Add(&M, &XX) + p.Z.Add(&p.Z, &p.Y). + Square(&p.Z). + Sub(&p.Z, &YY). + Sub(&p.Z, &ZZ) + T.Square(&M) + p.X = T + T.Double(&S) + p.X.Sub(&p.X, &T) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M) + YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY) + p.Y.Sub(&p.Y, &YYYY) + + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { + return p.mulGLV(a, s) +} + +// String returns canonical representation of the point in affine coordinates +func (p *G2Jac) String() string { + _p := G2Affine{} + _p.FromJacobian(p) + return _p.String() +} + +// FromAffine sets p = Q, p in Jacobian, Q in affine +func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { + if Q.IsInfinity() { + p.Z.SetZero() + p.X.SetOne() + p.Y.SetOne() + return p + } + p.Z.SetOne() + p.X.Set(&Q.X) + p.Y.Set(&Q.Y) + return p +} + +// IsOnCurve returns true if p in on the curve +func (p *G2Jac) IsOnCurve() bool { + var left, right, tmp fptower.E2 + left.Square(&p.Y) + right.Square(&p.X).Mul(&right, &p.X) + tmp.Square(&p.Z). + Square(&tmp). + Mul(&tmp, &p.Z). + Mul(&tmp, &p.Z). + Mul(&tmp, &bTwistCurveCoeff) + right.Add(&right, &tmp) + return left.Equal(&right) +} + +// IsInSubGroup returns true if p is on the r-torsion, false otherwise. +// https://eprint.iacr.org/2021/1130.pdf, sec.4 +// and https://eprint.iacr.org/2022/352.pdf, sec. 4.2 +// ψ(p) = [x₀]P +func (p *G2Jac) IsInSubGroup() bool { + var res, tmp G2Jac + tmp.psi(p) + res.ScalarMultiplication(p, &xGen). + AddAssign(&tmp) + + return res.IsOnCurve() && res.Z.IsZero() +} + +// mulWindowed computes a 2-bits windowed scalar multiplication +func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { + + var res G2Jac + var ops [3]G2Jac + + ops[0].Set(a) + if s.Sign() == -1 { + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) + ops[1].Double(&ops[0]) + ops[2].Set(&ops[0]).AddAssign(&ops[1]) + + b := s.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.DoubleAssign().DoubleAssign() + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.AddAssign(&ops[c-1]) + } + mask = mask >> 2 + } + } + p.Set(&res) + + return p + +} + +// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E +func (p *G2Jac) psi(a *G2Jac) *G2Jac { + p.Set(a) + p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) + p.Y.Conjugate(&p.Y).Mul(&p.Y, &endo.v) + p.Z.Conjugate(&p.Z) + return p +} + +// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p +// where w is a third root of unity in 𝔽p +func (p *G2Jac) phi(a *G2Jac) *G2Jac { + p.Set(a) + p.X.MulByElement(&p.X, &thirdRootOneG2) + return p +} + +// mulGLV computes the scalar multiplication using a windowed-GLV method +// see https://www.iacr.org/archive/crypto2001/21390189.pdf +func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { + + var table [15]G2Jac + var res G2Jac + var k1, k2 fr.Element + + res.Set(&g2Infinity) + + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a + table[0].Set(a) + table[3].phi(a) + + // split the scalar, modifies ±a, ϕ(a) accordingly + k := ecc.SplitScalar(s, &glvBasis) + + if k[0].Sign() == -1 { + k[0].Neg(&k[0]) + table[0].Neg(&table[0]) + } + if k[1].Sign() == -1 { + k[1].Neg(&k[1]) + table[3].Neg(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max + // this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift + k1 = k1.SetBigInt(&k[0]).Bits() + k2 = k2.SetBigInt(&k[1]).Bits() + + // we don't target constant-timeness so we check first if we increase the bounds or not + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (k1[i] & mask) >> (62 - 2*j) + b2 := (k2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G2Affine) ClearCofactor(a *G2Affine) *G2Affine { + var _p G2Jac + _p.FromAffine(a) + _p.ClearCofactor(&_p) + p.FromJacobian(&_p) + return p +} + +// ClearCofactor maps a point in curve to r-torsion +func (p *G2Jac) ClearCofactor(a *G2Jac) *G2Jac { + // https://eprint.iacr.org/2017/419.pdf, 4.1 + var xg, xxg, res, t G2Jac + xg.ScalarMultiplication(a, &xGen).Neg(&xg) + xxg.ScalarMultiplication(&xg, &xGen).Neg(&xxg) + + res.Set(&xxg). + SubAssign(&xg). + SubAssign(a) + + t.Set(&xg). + SubAssign(a). + psi(&t) + + res.AddAssign(&t) + + t.Double(a) + t.X.MulByElement(&t.X, &thirdRootOneG1) + + res.SubAssign(&t) + + p.Set(&res) + + return p + +} + +// ------------------------------------------------------------------------------------------------- +// Jacobian extended + +// Set sets p to the provided point +func (p *g2JacExtended) Set(a *g2JacExtended) *g2JacExtended { + p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ + return p +} + +// setInfinity sets p to O +func (p *g2JacExtended) setInfinity() *g2JacExtended { + p.X.SetOne() + p.Y.SetOne() + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p +} + +func (p *g2JacExtended) IsZero() bool { + return p.ZZ.IsZero() +} + +// fromJacExtended sets Q in affine coordinates +func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { + if Q.ZZ.IsZero() { + p.X = fptower.E2{} + p.Y = fptower.E2{} + return p + } + p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) + return p +} + +// fromJacExtended sets Q in Jacobian coordinates +func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { + if Q.ZZ.IsZero() { + p.Set(&g2Infinity) + return p + } + p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) + p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) + p.Z.Set(&Q.ZZZ) + return p +} + +// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity +func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { + p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) + p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) + p.Z = Q.ZZZ + return p +} + +// add point in Jacobian extended coordinates +// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s +func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { + //if q is infinity return p + if q.ZZ.IsZero() { + return p + } + // p is infinity, return q + if p.ZZ.IsZero() { + p.Set(q) + return p + } + + var A, B, U1, U2, S1, S2 fptower.E2 + + // p2: q, p1: p + U2.Mul(&q.X, &p.ZZ) + U1.Mul(&p.X, &q.ZZ) + A.Sub(&U2, &U1) + S2.Mul(&q.Y, &p.ZZZ) + S1.Mul(&p.Y, &q.ZZZ) + B.Sub(&S2, &S1) + + if A.IsZero() { + if B.IsZero() { + return p.double(q) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var P, R, PP, PPP, Q, V fptower.E2 + P.Sub(&U2, &U1) + R.Sub(&S2, &S1) + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&U1, &PP) + V.Mul(&S1, &PPP) + + p.X.Square(&R). + Sub(&p.X, &PPP). + Sub(&p.X, &Q). + Sub(&p.X, &Q) + p.Y.Sub(&Q, &p.X). + Mul(&p.Y, &R). + Sub(&p.Y, &V) + p.ZZ.Mul(&p.ZZ, &q.ZZ). + Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &q.ZZZ). + Mul(&p.ZZZ, &PPP) + + return p +} + +// double point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +// since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well +func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { + var U, V, W, S, XX, M fptower.E2 + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + U.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S). + Sub(&p.X, &S) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &U) + p.ZZ.Mul(&V, &q.ZZ) + p.ZZZ.Mul(&W, &q.ZZZ) + + return p +} + +// subMixed same as addMixed, but will negate a.Y +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y.Neg(&a.Y) + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fptower.E2 + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Neg(&R) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleNegMixed(a) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fptower.E2 + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// addMixed +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s +func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { + + //if a is infinity return p + if a.IsInfinity() { + return p + } + // p is infinity, return a + if p.ZZ.IsZero() { + p.X = a.X + p.Y = a.Y + p.ZZ.SetOne() + p.ZZZ.SetOne() + return p + } + + var P, R fptower.E2 + + // p2: a, p1: p + P.Mul(&a.X, &p.ZZ) + P.Sub(&P, &p.X) + + R.Mul(&a.Y, &p.ZZZ) + R.Sub(&R, &p.Y) + + if P.IsZero() { + if R.IsZero() { + return p.doubleMixed(a) + + } + p.ZZ = fptower.E2{} + p.ZZZ = fptower.E2{} + return p + } + + var PP, PPP, Q, Q2, RR, X3, Y3 fptower.E2 + + PP.Square(&P) + PPP.Mul(&P, &PP) + Q.Mul(&p.X, &PP) + RR.Square(&R) + X3.Sub(&RR, &PPP) + Q2.Double(&Q) + p.X.Sub(&X3, &Q2) + Y3.Sub(&Q, &p.X).Mul(&Y3, &R) + R.Mul(&p.Y, &PPP) + p.Y.Sub(&Y3, &R) + p.ZZ.Mul(&p.ZZ, &PP) + p.ZZZ.Mul(&p.ZZZ, &PPP) + + return p + +} + +// doubleNegMixed same as double, but will negate q.Y +func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { + + var U, V, W, S, XX, M, S2, L fptower.E2 + + U.Double(&q.Y) + U.Neg(&U) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Add(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// doubleMixed point in Jacobian extended coordinates +// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { + + var U, V, W, S, XX, M, S2, L fptower.E2 + + U.Double(&q.Y) + V.Square(&U) + W.Mul(&U, &V) + S.Mul(&q.X, &V) + XX.Square(&q.X) + M.Double(&XX). + Add(&M, &XX) // -> + a, but a=0 here + S2.Double(&S) + L.Mul(&W, &q.Y) + + p.X.Square(&M). + Sub(&p.X, &S2) + p.Y.Sub(&S, &p.X). + Mul(&p.Y, &M). + Sub(&p.Y, &L) + p.ZZ.Set(&V) + p.ZZZ.Set(&W) + + return p +} + +// ------------------------------------------------------------------------------------------------- +// Homogenous projective + +// Set sets p to the provided point +func (p *g2Proj) Set(a *g2Proj) *g2Proj { + p.x, p.y, p.z = a.x, a.y, a.z + return p +} + +// Neg computes -G +func (p *g2Proj) Neg(a *g2Proj) *g2Proj { + *p = *a + p.y.Neg(&a.y) + return p +} + +// FromAffine sets p = Q, p in homogenous projective, Q in affine +func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { + if Q.X.IsZero() && Q.Y.IsZero() { + p.z.SetZero() + p.x.SetOne() + p.y.SetOne() + return p + } + p.z.SetOne() + p.x.Set(&Q.X) + p.y.Set(&Q.Y) + return p +} + +// BatchScalarMultiplicationG2 multiplies the same base by all scalars +// and return resulting points in affine coordinates +// uses a simple windowed-NAF like exponentiation algorithm +func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { + // approximate cost in group ops is + // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) + + nbPoints := uint64(len(scalars)) + min := ^uint64(0) + bestC := 0 + for c := 2; c <= 16; c++ { + cost := uint64(1 << (c - 1)) // pre compute the table + nbChunks := computeNbChunks(uint64(c)) + cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add + if cost < min { + min = cost + bestC = c + } + } + c := uint64(bestC) // window size + nbChunks := int(computeNbChunks(c)) + + // last window may be slightly larger than c; in which case we need to compute one + // extra element in the baseTable + maxC := lastC(c) + if c > maxC { + maxC = c + } + + // precompute all powers of base for our window + // note here that if performance is critical, we can implement as in the msmX methods + // this allocation to be on the stack + baseTable := make([]G2Jac, (1 << (maxC - 1))) + baseTable[0].FromAffine(base) + for i := 1; i < len(baseTable); i++ { + baseTable[i] = baseTable[i-1] + baseTable[i].AddMixed(base) + } + toReturn := make([]G2Affine, len(scalars)) + + // partition the scalars into digits + digits, _ := partitionScalars(scalars, c, runtime.NumCPU()) + + // for each digit, take value in the base table, double it c time, voilà. + parallel.Execute(len(scalars), func(start, end int) { + var p G2Jac + for i := start; i < end; i++ { + p.Set(&g2Infinity) + for chunk := nbChunks - 1; chunk >= 0; chunk-- { + if chunk != nbChunks-1 { + for j := uint64(0); j < c; j++ { + p.DoubleAssign() + } + } + offset := chunk * len(scalars) + digit := digits[i+offset] + + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + p.AddAssign(&baseTable[(digit>>1)-1]) + } else { + // sub + t := baseTable[digit>>1] + t.Neg(&t) + p.AddAssign(&t) + } + } + + // set our result point + toReturn[i].FromJacobian(&p) + + } + }) + return toReturn +} + +// batch add affine coordinates +// using batch inversion +// special cases (doubling, infinity) must be filtered out before this call +func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { + var lambda, lambdain TC + + // add part + for j := 0; j < batchSize; j++ { + lambdain[j].Sub(&(*P)[j].X, &(*R)[j].X) + } + + // invert denominator using montgomery batch invert technique + { + var accumulator fptower.E2 + lambda[0].SetOne() + accumulator.Set(&lambdain[0]) + + for i := 1; i < batchSize; i++ { + lambda[i] = accumulator + accumulator.Mul(&accumulator, &lambdain[i]) + } + + accumulator.Inverse(&accumulator) + + for i := batchSize - 1; i > 0; i-- { + lambda[i].Mul(&lambda[i], &accumulator) + accumulator.Mul(&accumulator, &lambdain[i]) + } + lambda[0].Set(&accumulator) + } + + var d fptower.E2 + var rr G2Affine + + // add part + for j := 0; j < batchSize; j++ { + // computa lambda + d.Sub(&(*P)[j].Y, &(*R)[j].Y) + lambda[j].Mul(&lambda[j], &d) + + // compute X, Y + rr.X.Square(&lambda[j]) + rr.X.Sub(&rr.X, &(*R)[j].X) + rr.X.Sub(&rr.X, &(*P)[j].X) + d.Sub(&(*R)[j].X, &rr.X) + rr.Y.Mul(&lambda[j], &d) + rr.Y.Sub(&rr.Y, &(*R)[j].Y) + (*R)[j].Set(&rr) + } +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g1.go new file mode 100644 index 00000000000..7152782835b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g1.go @@ -0,0 +1,340 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + + "math/big" +) + +//Note: This only works for simple extensions + +func g1IsogenyXNumerator(dst *fp.Element, x *fp.Element) { + g1EvalPolynomial(dst, + false, + []fp.Element{ + {5555391298090832668, 1871845530032595596, 4551034694774233518, 2584197799339864836, 15085749040064757844, 654075415717002996}, + {9910598932128054667, 4357765064159749802, 1555960221863322426, 9671461638228026285, 1275132148248838779, 507072521670460589}, + {11908177372061066827, 18190436643933350086, 6603102998733829542, 6581045210674032871, 16099974426311393401, 541581077397919012}, + {5282195870529824577, 12365729195083706401, 2807246122435955773, 332702220601507168, 7339422050895811209, 1050416448951884523}, + {10443415753526299973, 8852419397684277637, 1088333252544296036, 1174353327457337436, 1626144519293139599, 716651429285276662}, + {7916646322956281527, 11909818257232418749, 1455301921509471421, 3317627683558310107, 12693445337245173919, 1798273032850409769}, + {2577731109215284733, 8810166123993386985, 3186592767751348067, 15050850291391518479, 18435652654155870871, 1330813445865859326}, + {8787912969482053798, 9653629252694769025, 1358451377919714320, 16331599695590198629, 13519934665722691825, 628078949001449512}, + {16605411443261943819, 9536014432113026165, 8685402948537367476, 16291074259433785035, 407185289045737198, 713426768049972652}, + {1001421273809907975, 724433776290697394, 16309429154639760781, 10003715605277815375, 307249038158020985, 688008371043525493}, + {16622893420529658311, 18333652517857227637, 2139173376235292830, 16496634502105693419, 5355299366650241487, 382770009771704860}, + {8276255265012938363, 9997870203437298645, 16819210142450232135, 5062450688048499179, 12776432501206859311, 1778476024187613533}, + }, + x) +} + +func g1IsogenyXDenominator(dst *fp.Element, x *fp.Element) { + g1EvalPolynomial(dst, + true, + []fp.Element{ + {13358415881952098629, 12009257493157516192, 13928884382876484932, 12988314785833227070, 11244145530317148182, 100673949996487007}, + {2533162896381624793, 10578896196504721258, 4263020647280931071, 1255899686249737875, 17097124965295857733, 590960935246623182}, + {10990404485039254780, 5344458621503091696, 1718862119039451458, 11600049052019063549, 18389973225607751698, 1092616849767867362}, + {16377845895484993601, 15314247056264135931, 14543008873173635408, 4875476272346940127, 2030129768648768484, 1297689274107773964}, + {6376927397170316667, 1460555178565443615, 18156708192400235081, 14761117739963869762, 8361091377443400626, 1421233557303902229}, + {18127417459170613536, 5353764292720778676, 858818813615405862, 3528937506143354306, 12604964186779349896, 489837025077541867}, + {15285065477075910543, 3650488990300576179, 7274499670465195193, 16100555180954076900, 7580582425312971905, 896074979407586822}, + {7582945168915351799, 2506680954090651888, 10272835934257987876, 9924916350558121763, 13577194922650729507, 1698254565890367778}, + {2009730524583761661, 11053280693947850663, 14409256190409559425, 3658799329773368860, 13529638021208614900, 869243908766415668}, + {11058048790650732295, 7059501760293999296, 6596812464094265283, 14567744481299745071, 1591898617514919697, 1344004358835331304}, + }, + x) +} + +func g1IsogenyYNumerator(dst *fp.Element, x *fp.Element, y *fp.Element) { + var _dst fp.Element + g1EvalPolynomial(&_dst, + false, + []fp.Element{ + {3122824077082063463, 2111517899915568999, 14844585557031220083, 14713720721132803039, 9041847780307969683, 950267513573868304}, + {11079511902567680319, 18338468344530008184, 6769016392463638666, 1504264063027988936, 8098359051856762276, 760455062874047829}, + {1430247552210236986, 3854575382974307965, 14917507996414511245, 207936139448560, 9498310774218301406, 1438631746617682181}, + {6654065794071117243, 2928282753802966791, 4144383358731160429, 12673586709493869907, 12918170109018188791, 844088361957958231}, + {6416330705244672319, 3552017270878949117, 7777490944331917312, 7917192495177481567, 7271851377118683537, 253926972271069325}, + {11903306495973637341, 11622313950541285762, 17991208474928993001, 12280964980743791783, 14941570282955772167, 143516344770893715}, + {7324386472845891920, 16310961984705608217, 14050364318273732029, 410622978843904432, 13407944087243235067, 570579643952782879}, + {10655681039374273828, 3913226275392147601, 9613292388335178165, 11852815148890010639, 17652581670569921892, 780578093363976825}, + {10454026283255684948, 15005802245309313587, 4420421943175638630, 18052347756729021570, 12181908985148691767, 1485233717472293779}, + {5056344670784885274, 15896288289018563095, 11120951801157184493, 7250506164525313606, 9295677455526059106, 1757175036496698059}, + {417067620545670182, 113740147118943311, 7666319924200602156, 1469963335415292317, 13482947512490784447, 1353298443678343909}, + {13069093794065563159, 18364685236451803588, 2235996605706292724, 1007629142299662669, 4077244143222018961, 162586537120788900}, + {12976751790971550752, 10256454045927919861, 8968423978443605586, 91636529236982767, 9459527627289574163, 949550897353139410}, + {10595118024452621845, 8010256778549625402, 10333144214150401956, 17682229685967587631, 8235697699445463546, 317883997785997129}, + {16894283457285346118, 10513943172407809423, 4685513162956315481, 11558261883362075118, 574375951146893083, 1159440548124233311}, + {9739780494108151959, 17207219630538774058, 553911396609642498, 6085929320386029624, 14175410874026216616, 1183751611824804793}, + }, + x) + + dst.Mul(&_dst, y) +} + +func g1IsogenyYDenominator(dst *fp.Element, x *fp.Element) { + g1EvalPolynomial(dst, + true, + []fp.Element{ + {16963992846030154524, 1796759822929186144, 15995221960860457854, 8232142361908220707, 5977498266010213481, 759868220591477233}, + {7019489280640006651, 8025136855967848721, 17464762292772824538, 4490335113250743896, 7652702793653159798, 1129822927746498110}, + {3164260796573156764, 2639884922337322818, 1251365706181388855, 13142429936036186189, 359878619957828340, 126848055205862465}, + {17472832885692408710, 9911075278795900735, 2614390623136861791, 14474775734428698630, 6462878218464609418, 1225960780180864957}, + {3586995257703132870, 2143554115308730112, 15207899356205612465, 4372523065560113828, 12811868595146042778, 307251632623424763}, + {14298637377310410728, 10963101290308221781, 8192510423058716701, 1175370967867267532, 1029599188863854120, 678981456155013844}, + {11149806480082726900, 3664985661428410608, 18095361538178773836, 14174906593575241395, 15305104369759711886, 901234928011491053}, + {4727074327869776987, 15736954329525418288, 14642679026711520511, 11429849039208981702, 17333567062758618213, 951235897335772166}, + {9130114290642375589, 14069725355798443159, 6621984191700563591, 270173975669947883, 6218390495944243859, 1077419361593130421}, + {9144875514986933294, 16561351410666797616, 8591333879886582656, 15059370240386191395, 7834396448114781869, 946553772269403391}, + {17809450171377747225, 15896956440537434491, 8451524482089653422, 1694507265233574136, 18224201536921880842, 317503425606567070}, + {13940503876759740187, 8772047862193200131, 6080360161890657205, 7935486160089058373, 9407473295146243021, 1255078947940629503}, + {1160821217138360586, 13542760608074182996, 11595911004531652098, 18158686636947034451, 13330657138280564947, 1773960737279760188}, + {9132548444917292754, 16464415422105000789, 6319313500251671073, 12727658548847517900, 10985275115076354035, 1431541893474124246}, + {662485641082390837, 260809847827618849, 6177381409359357075, 18231947741742261351, 18128540110746580014, 1079107229429227022}, + }, + x) +} + +func g1Isogeny(p *G1Affine) { + + den := make([]fp.Element, 2) + + g1IsogenyYDenominator(&den[1], &p.X) + g1IsogenyXDenominator(&den[0], &p.X) + + g1IsogenyYNumerator(&p.Y, &p.X, &p.Y) + g1IsogenyXNumerator(&p.X, &p.X) + + den = fp.BatchInvert(den) + + p.X.Mul(&p.X, &den[0]) + p.Y.Mul(&p.Y, &den[1]) +} + +// g1SqrtRatio computes the square root of u/v and returns 0 iff u/v was indeed a quadratic residue +// if not, we get sqrt(Z * u / v). Recall that Z is non-residue +// If v = 0, u/v is meaningless and the output is unspecified, without raising an error. +// The main idea is that since the computation of the square root involves taking large powers of u/v, the inversion of v can be avoided +func g1SqrtRatio(z *fp.Element, u *fp.Element, v *fp.Element) uint64 { + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-optimized-sqrt_ratio-for-q- (3 mod 4) + var tv1 fp.Element + tv1.Square(v) // 1. tv1 = v² + var tv2 fp.Element + tv2.Mul(u, v) // 2. tv2 = u * v + tv1.Mul(&tv1, &tv2) // 3. tv1 = tv1 * tv2 + + var y1 fp.Element + { + var c1 big.Int + // c1 = 1000602388805416848354447456433976039139220704984751971333014534031007912622709466110671907282253916009473568139946 + c1.SetBytes([]byte{6, 128, 68, 122, 142, 95, 249, 166, 146, 198, 233, 237, 144, 210, 235, 53, 217, 29, 210, 225, 60, 225, 68, 175, 217, 204, 52, 168, 61, 172, 61, 137, 7, 170, 255, 255, 172, 84, 255, 255, 238, 127, 191, 255, 255, 255, 234, 170}) // c1 = (q - 3) / 4 # Integer arithmetic + + y1.Exp(tv1, &c1) // 4. y1 = tv1ᶜ¹ + } + + y1.Mul(&y1, &tv2) // 5. y1 = y1 * tv2 + + var y2 fp.Element + // c2 = sqrt(-Z) + tv3 := fp.Element{17544630987809824292, 17306709551153317753, 8299808889594647786, 5930295261504720397, 675038575008112577, 167386374569371918} + y2.Mul(&y1, &tv3) // 6. y2 = y1 * c2 + tv3.Square(&y1) // 7. tv3 = y1² + tv3.Mul(&tv3, v) // 8. tv3 = tv3 * v + isQNr := tv3.NotEqual(u) // 9. isQR = tv3 == u + z.Select(int(isQNr), &y1, &y2) // 10. y = CMOV(y2, y1, isQR) + return isQNr +} + +// g1MulByZ multiplies x by [11] and stores the result in z +func g1MulByZ(z *fp.Element, x *fp.Element) { + + res := *x + + res.Double(&res) + res.Double(&res) + res.Add(&res, x) + res.Double(&res) + res.Add(&res, x) + + *z = res +} + +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method +// MapToCurve1 implements the SSWU map +// No cofactor clearing or isogeny +func MapToCurve1(u *fp.Element) G1Affine { + + var sswuIsoCurveCoeffA = fp.Element{3415322872136444497, 9675504606121301699, 13284745414851768802, 2873609449387478652, 2897906769629812789, 1536947672689614213} + var sswuIsoCurveCoeffB = fp.Element{18129637713272545760, 11144507692959411567, 10108153527111632324, 9745270364868568433, 14587922135379007624, 469008097655535723} + + var tv1 fp.Element + tv1.Square(u) // 1. tv1 = u² + + //mul tv1 by Z + g1MulByZ(&tv1, &tv1) // 2. tv1 = Z * tv1 + + var tv2 fp.Element + tv2.Square(&tv1) // 3. tv2 = tv1² + tv2.Add(&tv2, &tv1) // 4. tv2 = tv2 + tv1 + + var tv3 fp.Element + var tv4 fp.Element + tv4.SetOne() + tv3.Add(&tv2, &tv4) // 5. tv3 = tv2 + 1 + tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6. tv3 = B * tv3 + + tv2NZero := g1NotZero(&tv2) + + // tv4 = Z + tv4 = fp.Element{9830232086645309404, 1112389714365644829, 8603885298299447491, 11361495444721768256, 5788602283869803809, 543934104870762216} + + tv2.Neg(&tv2) + tv4.Select(int(tv2NZero), &tv4, &tv2) // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + tv4.Mul(&tv4, &sswuIsoCurveCoeffA) // 8. tv4 = A * tv4 + + tv2.Square(&tv3) // 9. tv2 = tv3² + + var tv6 fp.Element + tv6.Square(&tv4) // 10. tv6 = tv4² + + var tv5 fp.Element + tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6 + + tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5 + tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3 + tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4 + + tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6 + tv2.Add(&tv2, &tv5) // 16. tv2 = tv2 + tv5 + + var x fp.Element + x.Mul(&tv1, &tv3) // 17. x = tv1 * tv3 + + var y1 fp.Element + gx1NSquare := g1SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + + var y fp.Element + y.Mul(&tv1, u) // 19. y = tv1 * u + + y.Mul(&y, &y1) // 20. y = y * y1 + + x.Select(int(gx1NSquare), &tv3, &x) // 21. x = CMOV(x, tv3, is_gx1_square) + y.Select(int(gx1NSquare), &y1, &y) // 22. y = CMOV(y, y1, is_gx1_square) + + y1.Neg(&y) + y.Select(int(g1Sgn0(u)^g1Sgn0(&y)), &y, &y1) + + // 23. e1 = sgn0(u) == sgn0(y) + // 24. y = CMOV(-y, y, e1) + + x.Div(&x, &tv4) // 25. x = x / tv4 + + return G1Affine{x, y} +} + +func g1EvalPolynomial(z *fp.Element, monic bool, coefficients []fp.Element, x *fp.Element) { + dst := coefficients[len(coefficients)-1] + + if monic { + dst.Add(&dst, x) + } + + for i := len(coefficients) - 2; i >= 0; i-- { + dst.Mul(&dst, x) + dst.Add(&dst, &coefficients[i]) + } + + z.Set(&dst) +} + +// g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields +// Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function +// The sign of an element is not obviously related to that of its Montgomery form +func g1Sgn0(z *fp.Element) uint64 { + + nonMont := z.Bits() + + // m == 1 + return nonMont[0] % 2 + +} + +// MapToG1 invokes the SSWU map, and guarantees that the result is in g1 +func MapToG1(u fp.Element) G1Affine { + res := MapToCurve1(&u) + //this is in an isogenous curve + g1Isogeny(&res) + res.ClearCofactor(&res) + return res +} + +// EncodeToG1 hashes a message to a point on the G1 curve using the SSWU map. +// It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func EncodeToG1(msg, dst []byte) (G1Affine, error) { + + var res G1Affine + u, err := fp.Hash(msg, dst, 1) + if err != nil { + return res, err + } + + res = MapToCurve1(&u[0]) + + //this is in an isogenous curve + g1Isogeny(&res) + res.ClearCofactor(&res) + return res, nil +} + +// HashToG1 hashes a message to a point on the G1 curve using the SSWU map. +// Slower than EncodeToG1, but usable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func HashToG1(msg, dst []byte) (G1Affine, error) { + u, err := fp.Hash(msg, dst, 2*1) + if err != nil { + return G1Affine{}, err + } + + Q0 := MapToCurve1(&u[0]) + Q1 := MapToCurve1(&u[1]) + + //TODO (perf): Add in E' first, then apply isogeny + g1Isogeny(&Q0) + g1Isogeny(&Q1) + + var _Q0, _Q1 G1Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1).AddAssign(&_Q0) + + _Q1.ClearCofactor(&_Q1) + + Q1.FromJacobian(&_Q1) + return Q1, nil +} + +func g1NotZero(x *fp.Element) uint64 { + + return x[0] | x[1] | x[2] | x[3] | x[4] | x[5] + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g2.go new file mode 100644 index 00000000000..4feafbfb140 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/hash_to_g2.go @@ -0,0 +1,409 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" + + "math/big" +) + +//Note: This only works for simple extensions + +func g2IsogenyXNumerator(dst *fptower.E2, x *fptower.E2) { + g2EvalPolynomial(dst, + false, + []fptower.E2{ + { + A0: fp.Element{5185457120960601698, 494647221959407934, 8971396042087821730, 324544954362548322, 14214792730224113654, 1405280679127738945}, + A1: fp.Element{5185457120960601698, 494647221959407934, 8971396042087821730, 324544954362548322, 14214792730224113654, 1405280679127738945}, + }, + { + A0: fp.Element{0}, + A1: fp.Element{6910023028261548496, 9745789443900091043, 7668299866710145304, 2432656849393633605, 2897729527445498821, 776645607375592125}, + }, + { + A0: fp.Element{724047465092313539, 15783990863276714670, 12824896677063784855, 15246381572572671516, 13186611051602728692, 1485475813959743803}, + A1: fp.Element{12678383550985550056, 4872894721950045521, 13057521970209848460, 10439700461551592610, 10672236800577525218, 388322803687796062}, + }, + { + A0: fp.Element{4659755689450087917, 1804066951354704782, 15570919779568036803, 15592734958806855601, 7597208057374167129, 1841438384006890194}, + A1: fp.Element{0}, + }, + }, + x) +} + +func g2IsogenyXDenominator(dst *fptower.E2, x *fptower.E2) { + g2EvalPolynomial(dst, + true, + []fptower.E2{ + { + A0: fp.Element{0}, + A1: fp.Element{2250392438786206615, 17463829474098544446, 14571211649711714824, 4495761442775821336, 258811604141191305, 357646605018048850}, + }, + { + A0: fp.Element{4933130441833534766, 15904462746612662304, 8034115857496836953, 12755092135412849606, 7007796720291435703, 252692002104915169}, + A1: fp.Element{8469300574244328829, 4752422838614097887, 17848302789776796362, 12930989898711414520, 16851051131888818207, 1621106615542624696}, + }, + }, + x) +} + +func g2IsogenyYNumerator(dst *fptower.E2, x *fptower.E2, y *fptower.E2) { + var _dst fptower.E2 + g2EvalPolynomial(&_dst, + false, + []fptower.E2{ + { + A0: fp.Element{10869708750642247614, 13056187057366814946, 1750362034917495549, 6326189602300757217, 1140223926335695785, 632761649765668291}, + A1: fp.Element{10869708750642247614, 13056187057366814946, 1750362034917495549, 6326189602300757217, 1140223926335695785, 632761649765668291}, + }, + { + A0: fp.Element{0}, + A1: fp.Element{13765940311003083782, 5579209876153186557, 11349908400803699438, 11707848830955952341, 199199289641242246, 899896674917908607}, + }, + { + A0: fp.Element{15562563812347550836, 2436447360975022760, 6528760985104924230, 5219850230775796305, 5336118400288762609, 194161401843898031}, + A1: fp.Element{16286611277439864375, 18220438224251737430, 906913588459157469, 2019487729638916206, 75985378181939686, 1679637215803641835}, + }, + { + A0: fp.Element{11849179119594500956, 13906615243538674725, 14543197362847770509, 2041759640812427310, 2879701092679313252, 1259985822978576468}, + A1: fp.Element{0}, + }, + }, + x) + + dst.Mul(&_dst, y) +} + +func g2IsogenyYDenominator(dst *fptower.E2, x *fptower.E2) { + g2EvalPolynomial(dst, + true, + []fptower.E2{ + { + A0: fp.Element{99923616639376095, 10339114964526300021, 6204619029868000785, 1288486622530663893, 14587509920085997152, 272081012460753233}, + A1: fp.Element{99923616639376095, 10339114964526300021, 6204619029868000785, 1288486622530663893, 14587509920085997152, 272081012460753233}, + }, + { + A0: fp.Element{0}, + A1: fp.Element{6751177316358619845, 15498000274876530106, 6820146801716041242, 13487284328327464010, 776434812423573915, 1072939815054146550}, + }, + { + A0: fp.Element{7399695662750302149, 14633322083064217648, 12051173786245255430, 9909266166264498601, 1288323043582377747, 379038003157372754}, + A1: fp.Element{6002735353327561446, 6023563502162542543, 13831244861028377885, 15776815867859765525, 4123780734888324547, 1494760614490167112}, + }, + }, + x) +} + +func g2Isogeny(p *G2Affine) { + + den := make([]fptower.E2, 2) + + g2IsogenyYDenominator(&den[1], &p.X) + g2IsogenyXDenominator(&den[0], &p.X) + + g2IsogenyYNumerator(&p.Y, &p.X, &p.Y) + g2IsogenyXNumerator(&p.X, &p.X) + + den = fptower.BatchInvertE2(den) + + p.X.Mul(&p.X, &den[0]) + p.Y.Mul(&p.Y, &den[1]) +} + +// g2SqrtRatio computes the square root of u/v and returns 0 iff u/v was indeed a quadratic residue +// if not, we get sqrt(Z * u / v). Recall that Z is non-residue +// If v = 0, u/v is meaningless and the output is unspecified, without raising an error. +// The main idea is that since the computation of the square root involves taking large powers of u/v, the inversion of v can be avoided +func g2SqrtRatio(z *fptower.E2, u *fptower.E2, v *fptower.E2) uint64 { + + // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-sqrt_ratio-for-any-field + + tv1 := fptower.E2{ + A0: fp.Element{8921533702591418330, 15859389534032789116, 3389114680249073393, 15116930867080254631, 3288288975085550621, 1021049300055853010}, + A1: fp.Element{8921533702591418330, 15859389534032789116, 3389114680249073393, 15116930867080254631, 3288288975085550621, 1021049300055853010}, + } //tv1 = c6 + + var tv2, tv3, tv4, tv5 fptower.E2 + var exp big.Int + // c4 = 7 = 2³ - 1 + // q is odd so c1 is at least 1. + exp.SetBytes([]byte{7}) + + tv2.Exp(*v, &exp) // 2. tv2 = vᶜ⁴ + tv3.Square(&tv2) // 3. tv3 = tv2² + tv3.Mul(&tv3, v) // 4. tv3 = tv3 * v + tv5.Mul(u, &tv3) // 5. tv5 = u * tv3 + + // c3 = 1001205140483106588246484290269935788605945006208159541241399033561623546780709821462541004956387089373434649096260670658193992783731681621012512651314777238193313314641988297376025498093520728838658813979860931248214124593092835 + exp.SetBytes([]byte{42, 67, 122, 75, 140, 53, 252, 116, 189, 39, 142, 170, 34, 242, 94, 158, 45, 201, 14, 80, 231, 4, 107, 70, 110, 89, 228, 147, 73, 232, 189, 5, 10, 98, 207, 209, 109, 220, 166, 239, 83, 20, 147, 48, 151, 142, 240, 17, 214, 134, 25, 200, 97, 133, 199, 178, 146, 232, 90, 135, 9, 26, 4, 150, 107, 249, 30, 211, 231, 27, 116, 49, 98, 195, 56, 54, 33, 19, 207, 215, 206, 214, 177, 215, 99, 130, 234, 178, 106, 160, 0, 1, 199, 24, 227}) + + tv5.Exp(tv5, &exp) // 6. tv5 = tv5ᶜ³ + tv5.Mul(&tv5, &tv2) // 7. tv5 = tv5 * tv2 + tv2.Mul(&tv5, v) // 8. tv2 = tv5 * v + tv3.Mul(&tv5, u) // 9. tv3 = tv5 * u + tv4.Mul(&tv3, &tv2) // 10. tv4 = tv3 * tv2 + + // c5 = 4 + exp.SetBytes([]byte{4}) + tv5.Exp(tv4, &exp) // 11. tv5 = tv4ᶜ⁵ + isQNr := g2NotOne(&tv5) // 12. isQR = tv5 == 1 + c7 := fptower.E2{ + A0: fp.Element{1921729236329761493, 9193968980645934504, 9862280504246317678, 6861748847800817560, 10375788487011937166, 4460107375738415}, + A1: fp.Element{16821121318233475459, 10183025025229892778, 1779012082459463630, 3442292649700377418, 1061500799026501234, 1352426537312017168}, + } + tv2.Mul(&tv3, &c7) // 13. tv2 = tv3 * c7 + tv5.Mul(&tv4, &tv1) // 14. tv5 = tv4 * tv1 + tv3.Select(int(isQNr), &tv3, &tv2) // 15. tv3 = CMOV(tv2, tv3, isQR) + tv4.Select(int(isQNr), &tv4, &tv5) // 16. tv4 = CMOV(tv5, tv4, isQR) + exp.Lsh(big.NewInt(1), 3-2) // 18, 19: tv5 = 2ⁱ⁻² for i = c1 + + for i := 3; i >= 2; i-- { // 17. for i in (c1, c1 - 1, ..., 2): + + tv5.Exp(tv4, &exp) // 20. tv5 = tv4ᵗᵛ⁵ + nE1 := g2NotOne(&tv5) // 21. e1 = tv5 == 1 + tv2.Mul(&tv3, &tv1) // 22. tv2 = tv3 * tv1 + tv1.Mul(&tv1, &tv1) // 23. tv1 = tv1 * tv1 Why not write square? + tv5.Mul(&tv4, &tv1) // 24. tv5 = tv4 * tv1 + tv3.Select(int(nE1), &tv3, &tv2) // 25. tv3 = CMOV(tv2, tv3, e1) + tv4.Select(int(nE1), &tv4, &tv5) // 26. tv4 = CMOV(tv5, tv4, e1) + + if i > 2 { + exp.Rsh(&exp, 1) // 18, 19. tv5 = 2ⁱ⁻² + } + } + + *z = tv3 + return isQNr +} + +func g2NotOne(x *fptower.E2) uint64 { + + //Assuming hash is implemented for G1 and that the curve is over Fp + var one fp.Element + return one.SetOne().NotEqual(&x.A0) | g1NotZero(&x.A1) + +} + +// g2MulByZ multiplies x by [-2, -1] and stores the result in z +func g2MulByZ(z *fptower.E2, x *fptower.E2) { + + z.Mul(x, &fptower.E2{ + A0: fp.Element{9794203289623549276, 7309342082925068282, 1139538881605221074, 15659550692327388916, 16008355200866287827, 582484205531694093}, + A1: fp.Element{4897101644811774638, 3654671041462534141, 569769440802610537, 17053147383018470266, 17227549637287919721, 291242102765847046}, + }) + +} + +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method +// MapToCurve2 implements the SSWU map +// No cofactor clearing or isogeny +func MapToCurve2(u *fptower.E2) G2Affine { + + var sswuIsoCurveCoeffA = fptower.E2{ + A0: fp.Element{0}, + A1: fp.Element{16517514583386313282, 74322656156451461, 16683759486841714365, 815493829203396097, 204518332920448171, 1306242806803223655}, + } + var sswuIsoCurveCoeffB = fptower.E2{ + A0: fp.Element{2515823342057463218, 7982686274772798116, 7934098172177393262, 8484566552980779962, 4455086327883106868, 1323173589274087377}, + A1: fp.Element{2515823342057463218, 7982686274772798116, 7934098172177393262, 8484566552980779962, 4455086327883106868, 1323173589274087377}, + } + + var tv1 fptower.E2 + tv1.Square(u) // 1. tv1 = u² + + //mul tv1 by Z + g2MulByZ(&tv1, &tv1) // 2. tv1 = Z * tv1 + + var tv2 fptower.E2 + tv2.Square(&tv1) // 3. tv2 = tv1² + tv2.Add(&tv2, &tv1) // 4. tv2 = tv2 + tv1 + + var tv3 fptower.E2 + var tv4 fptower.E2 + tv4.SetOne() + tv3.Add(&tv2, &tv4) // 5. tv3 = tv2 + 1 + tv3.Mul(&tv3, &sswuIsoCurveCoeffB) // 6. tv3 = B * tv3 + + tv2NZero := g2NotZero(&tv2) + + // tv4 = Z + tv4 = fptower.E2{ + A0: fp.Element{9794203289623549276, 7309342082925068282, 1139538881605221074, 15659550692327388916, 16008355200866287827, 582484205531694093}, + A1: fp.Element{4897101644811774638, 3654671041462534141, 569769440802610537, 17053147383018470266, 17227549637287919721, 291242102765847046}, + } + + tv2.Neg(&tv2) + tv4.Select(int(tv2NZero), &tv4, &tv2) // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) + tv4.Mul(&tv4, &sswuIsoCurveCoeffA) // 8. tv4 = A * tv4 + + tv2.Square(&tv3) // 9. tv2 = tv3² + + var tv6 fptower.E2 + tv6.Square(&tv4) // 10. tv6 = tv4² + + var tv5 fptower.E2 + tv5.Mul(&tv6, &sswuIsoCurveCoeffA) // 11. tv5 = A * tv6 + + tv2.Add(&tv2, &tv5) // 12. tv2 = tv2 + tv5 + tv2.Mul(&tv2, &tv3) // 13. tv2 = tv2 * tv3 + tv6.Mul(&tv6, &tv4) // 14. tv6 = tv6 * tv4 + + tv5.Mul(&tv6, &sswuIsoCurveCoeffB) // 15. tv5 = B * tv6 + tv2.Add(&tv2, &tv5) // 16. tv2 = tv2 + tv5 + + var x fptower.E2 + x.Mul(&tv1, &tv3) // 17. x = tv1 * tv3 + + var y1 fptower.E2 + gx1NSquare := g2SqrtRatio(&y1, &tv2, &tv6) // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + + var y fptower.E2 + y.Mul(&tv1, u) // 19. y = tv1 * u + + y.Mul(&y, &y1) // 20. y = y * y1 + + x.Select(int(gx1NSquare), &tv3, &x) // 21. x = CMOV(x, tv3, is_gx1_square) + y.Select(int(gx1NSquare), &y1, &y) // 22. y = CMOV(y, y1, is_gx1_square) + + y1.Neg(&y) + y.Select(int(g2Sgn0(u)^g2Sgn0(&y)), &y, &y1) + + // 23. e1 = sgn0(u) == sgn0(y) + // 24. y = CMOV(-y, y, e1) + + x.Div(&x, &tv4) // 25. x = x / tv4 + + return G2Affine{x, y} +} + +func g2EvalPolynomial(z *fptower.E2, monic bool, coefficients []fptower.E2, x *fptower.E2) { + dst := coefficients[len(coefficients)-1] + + if monic { + dst.Add(&dst, x) + } + + for i := len(coefficients) - 2; i >= 0; i-- { + dst.Mul(&dst, x) + dst.Add(&dst, &coefficients[i]) + } + + z.Set(&dst) +} + +// g2Sgn0 is an algebraic substitute for the notion of sign in ordered fields +// Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function +// The sign of an element is not obviously related to that of its Montgomery form +func g2Sgn0(z *fptower.E2) uint64 { + + nonMont := z.Bits() + + sign := uint64(0) // 1. sign = 0 + zero := uint64(1) // 2. zero = 1 + var signI uint64 + var zeroI uint64 + + // 3. i = 1 + signI = nonMont.A0[0] % 2 // 4. sign_i = x_i mod 2 + zeroI = g1NotZero(&nonMont.A0) + zeroI = 1 ^ (zeroI|-zeroI)>>63 // 5. zero_i = x_i == 0 + sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops + zero = zero & zeroI // 7. zero = zero AND zero_i + // 3. i = 2 + signI = nonMont.A1[0] % 2 // 4. sign_i = x_i mod 2 + // 5. zero_i = x_i == 0 + sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops + // 7. zero = zero AND zero_i + return sign + +} + +// MapToG2 invokes the SSWU map, and guarantees that the result is in g2 +func MapToG2(u fptower.E2) G2Affine { + res := MapToCurve2(&u) + //this is in an isogenous curve + g2Isogeny(&res) + res.ClearCofactor(&res) + return res +} + +// EncodeToG2 hashes a message to a point on the G2 curve using the SSWU map. +// It is faster than HashToG2, but the result is not uniformly distributed. Unsuitable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func EncodeToG2(msg, dst []byte) (G2Affine, error) { + + var res G2Affine + u, err := fp.Hash(msg, dst, 2) + if err != nil { + return res, err + } + + res = MapToCurve2(&fptower.E2{ + A0: u[0], + A1: u[1], + }) + + //this is in an isogenous curve + g2Isogeny(&res) + res.ClearCofactor(&res) + return res, nil +} + +// HashToG2 hashes a message to a point on the G2 curve using the SSWU map. +// Slower than EncodeToG2, but usable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func HashToG2(msg, dst []byte) (G2Affine, error) { + u, err := fp.Hash(msg, dst, 2*2) + if err != nil { + return G2Affine{}, err + } + + Q0 := MapToCurve2(&fptower.E2{ + A0: u[0], + A1: u[1], + }) + Q1 := MapToCurve2(&fptower.E2{ + A0: u[2+0], + A1: u[2+1], + }) + + //TODO (perf): Add in E' first, then apply isogeny + g2Isogeny(&Q0) + g2Isogeny(&Q1) + + var _Q0, _Q1 G2Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1).AddAssign(&_Q0) + + _Q1.ClearCofactor(&_Q1) + + Q1.FromJacobian(&_Q1) + return Q1, nil +} + +func g2NotZero(x *fptower.E2) uint64 { + //Assuming G1 is over Fp and that if hashing is available for G2, it also is for G1 + return g1NotZero(&x.A0) | g1NotZero(&x.A1) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm.go new file mode 100644 index 00000000000..49751a93969 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm.go @@ -0,0 +1,28 @@ +//go:build !noadx +// +build !noadx + +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import "golang.org/x/sys/cpu" + +// supportAdx will be set only on amd64 that has MULX and ADDX instructions +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx // used in asm +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm_noadx.go new file mode 100644 index 00000000000..c6a97081fca --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm_noadx.go @@ -0,0 +1,25 @@ +//go:build noadx +// +build noadx + +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var supportAdx = false diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12.go new file mode 100644 index 00000000000..095a79a4c09 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12.go @@ -0,0 +1,862 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import ( + "errors" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "math/big" + "sync" +) + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +// E12 is a degree two finite field extension of fp6 +type E12 struct { + C0, C1 E6 +} + +// Equal returns true if z equals x, false otherwise +func (z *E12) Equal(x *E12) bool { + return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) +} + +// String puts E12 in string form +func (z *E12) String() string { + return (z.C0.String() + "+(" + z.C1.String() + ")*w") +} + +// SetString sets a E12 from string +func (z *E12) SetString(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11 string) *E12 { + z.C0.SetString(s0, s1, s2, s3, s4, s5) + z.C1.SetString(s6, s7, s8, s9, s10, s11) + return z +} + +// Set copies x into z and returns z +func (z *E12) Set(x *E12) *E12 { + z.C0 = x.C0 + z.C1 = x.C1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E12) SetOne() *E12 { + *z = E12{} + z.C0.B0.A0.SetOne() + return z +} + +// Add set z=x+y in E12 and return z +func (z *E12) Add(x, y *E12) *E12 { + z.C0.Add(&x.C0, &y.C0) + z.C1.Add(&x.C1, &y.C1) + return z +} + +// Sub sets z to x sub y and return z +func (z *E12) Sub(x, y *E12) *E12 { + z.C0.Sub(&x.C0, &y.C0) + z.C1.Sub(&x.C1, &y.C1) + return z +} + +// Double sets z=2*x and returns z +func (z *E12) Double(x *E12) *E12 { + z.C0.Double(&x.C0) + z.C1.Double(&x.C1) + return z +} + +// SetRandom used only in tests +func (z *E12) SetRandom() (*E12, error) { + if _, err := z.C0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.C1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if the two elements are equal, false otherwise +func (z *E12) IsZero() bool { + return z.C0.IsZero() && z.C1.IsZero() +} + +func (z *E12) IsOne() bool { + return z.C0.IsOne() && z.C1.IsZero() +} + +// Mul set z=x*y in E12 and return z +func (z *E12) Mul(x, y *E12) *E12 { + var a, b, c E6 + a.Add(&x.C0, &x.C1) + b.Add(&y.C0, &y.C1) + a.Mul(&a, &b) + b.Mul(&x.C0, &y.C0) + c.Mul(&x.C1, &y.C1) + z.C1.Sub(&a, &b).Sub(&z.C1, &c) + z.C0.MulByNonResidue(&c).Add(&z.C0, &b) + return z +} + +// Square set z=x*x in E12 and return z +func (z *E12) Square(x *E12) *E12 { + + //Algorithm 22 from https://eprint.iacr.org/2010/354.pdf + var c0, c2, c3 E6 + c0.Sub(&x.C0, &x.C1) + c3.MulByNonResidue(&x.C1).Neg(&c3).Add(&x.C0, &c3) + c2.Mul(&x.C0, &x.C1) + c0.Mul(&c0, &c3).Add(&c0, &c2) + z.C1.Double(&c2) + c2.MulByNonResidue(&c2) + z.C0.Add(&c0, &c2) + + return z +} + +// Karabina's compressed cyclotomic square +// https://eprint.iacr.org/2010/542.pdf +// Th. 3.2 with minor modifications to fit our tower +func (z *E12) CyclotomicSquareCompressed(x *E12) *E12 { + + var t [7]E2 + + // t0 = g1^2 + t[0].Square(&x.C0.B1) + // t1 = g5^2 + t[1].Square(&x.C1.B2) + // t5 = g1 + g5 + t[5].Add(&x.C0.B1, &x.C1.B2) + // t2 = (g1 + g5)^2 + t[2].Square(&t[5]) + + // t3 = g1^2 + g5^2 + t[3].Add(&t[0], &t[1]) + // t5 = 2 * g1 * g5 + t[5].Sub(&t[2], &t[3]) + + // t6 = g3 + g2 + t[6].Add(&x.C1.B0, &x.C0.B2) + // t3 = (g3 + g2)^2 + t[3].Square(&t[6]) + // t2 = g3^2 + t[2].Square(&x.C1.B0) + + // t6 = 2 * nr * g1 * g5 + t[6].MulByNonResidue(&t[5]) + // t5 = 4 * nr * g1 * g5 + 2 * g3 + t[5].Add(&t[6], &x.C1.B0). + Double(&t[5]) + // z3 = 6 * nr * g1 * g5 + 2 * g3 + z.C1.B0.Add(&t[5], &t[6]) + + // t4 = nr * g5^2 + t[4].MulByNonResidue(&t[1]) + // t5 = nr * g5^2 + g1^2 + t[5].Add(&t[0], &t[4]) + // t6 = nr * g5^2 + g1^2 - g2 + t[6].Sub(&t[5], &x.C0.B2) + + // t1 = g2^2 + t[1].Square(&x.C0.B2) + + // t6 = 2 * nr * g5^2 + 2 * g1^2 - 2*g2 + t[6].Double(&t[6]) + // z2 = 3 * nr * g5^2 + 3 * g1^2 - 2*g2 + z.C0.B2.Add(&t[6], &t[5]) + + // t4 = nr * g2^2 + t[4].MulByNonResidue(&t[1]) + // t5 = g3^2 + nr * g2^2 + t[5].Add(&t[2], &t[4]) + // t6 = g3^2 + nr * g2^2 - g1 + t[6].Sub(&t[5], &x.C0.B1) + // t6 = 2 * g3^2 + 2 * nr * g2^2 - 2 * g1 + t[6].Double(&t[6]) + // z1 = 3 * g3^2 + 3 * nr * g2^2 - 2 * g1 + z.C0.B1.Add(&t[6], &t[5]) + + // t0 = g2^2 + g3^2 + t[0].Add(&t[2], &t[1]) + // t5 = 2 * g3 * g2 + t[5].Sub(&t[3], &t[0]) + // t6 = 2 * g3 * g2 + g5 + t[6].Add(&t[5], &x.C1.B2) + // t6 = 4 * g3 * g2 + 2 * g5 + t[6].Double(&t[6]) + // z5 = 6 * g3 * g2 + 2 * g5 + z.C1.B2.Add(&t[5], &t[6]) + + return z +} + +// DecompressKarabina Karabina's cyclotomic square result +// if g3 != 0 +// +// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 +// +// if g3 == 0 +// +// g4 = 2g1g5/g2 +// +// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) +// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} +func (z *E12) DecompressKarabina(x *E12) *E12 { + + var t [3]E2 + var one E2 + one.SetOne() + + if x.C1.B2.IsZero() /* g3 == 0 */ { + t[0].Mul(&x.C0.B1, &x.C1.B2). + Double(&t[0]) + // t1 = g2 + t[1].Set(&x.C0.B2) + + if t[1].IsZero() /* g2 == g3 == 0 */ { + return z.SetOne() + } + } else /* g3 != 0 */ { + + // t0 = g1^2 + t[0].Square(&x.C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t[1].Sub(&t[0], &x.C0.B2). + Double(&t[1]). + Add(&t[1], &t[0]) + // t0 = E * g5^2 + t1 + t[2].Square(&x.C1.B2) + t[0].MulByNonResidue(&t[2]). + Add(&t[0], &t[1]) + // t1 = 4 * g3 + t[1].Double(&x.C1.B0). + Double(&t[1]) + } + + // z4 = g4 + z.C1.B1.Div(&t[0], &t[1]) // costly + + // t1 = g2 * g1 + t[1].Mul(&x.C0.B2, &x.C0.B1) + // t2 = 2 * g4^2 - 3 * g2 * g1 + t[2].Square(&z.C1.B1). + Sub(&t[2], &t[1]). + Double(&t[2]). + Sub(&t[2], &t[1]) + // t1 = g3 * g5 (g3 can be 0) + t[1].Mul(&x.C1.B0, &x.C1.B2) + // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + t[2].Add(&t[2], &t[1]) + z.C0.B0.MulByNonResidue(&t[2]). + Add(&z.C0.B0, &one) + + z.C0.B1.Set(&x.C0.B1) + z.C0.B2.Set(&x.C0.B2) + z.C1.B0.Set(&x.C1.B0) + z.C1.B2.Set(&x.C1.B2) + + return z +} + +// BatchDecompressKarabina multiple Karabina's cyclotomic square results +// if g3 != 0 +// +// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 +// +// if g3 == 0 +// +// g4 = 2g1g5/g2 +// +// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) +// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} +// +// Divisions by 4g3 or g2 is batched using Montgomery batch inverse +func BatchDecompressKarabina(x []E12) []E12 { + + n := len(x) + if n == 0 { + return x + } + + t0 := make([]E2, n) + t1 := make([]E2, n) + t2 := make([]E2, n) + zeroes := make([]bool, n) + + var one E2 + one.SetOne() + + for i := 0; i < n; i++ { + if x[i].C1.B2.IsZero() /* g3 == 0 */ { + t0[i].Mul(&x[i].C0.B1, &x[i].C1.B2). + Double(&t0[i]) + // t1 = g2 + t1[i].Set(&x[i].C0.B2) + + if t1[i].IsZero() /* g3 == g2 == 0 */ { + x[i].SetOne() + zeroes[i] = true + continue + } + } else /* g3 != 0 */ { + // t0 = g1^2 + t0[i].Square(&x[i].C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t1[i].Sub(&t0[i], &x[i].C0.B2). + Double(&t1[i]). + Add(&t1[i], &t0[i]) + // t0 = E * g5^2 + t1 + t2[i].Square(&x[i].C1.B2) + t0[i].MulByNonResidue(&t2[i]). + Add(&t0[i], &t1[i]) + // t1 = 4 * g3 + t1[i].Double(&x[i].C1.B0). + Double(&t1[i]) + } + } + + t1 = BatchInvertE2(t1) // costs 1 inverse + + for i := 0; i < n; i++ { + if zeroes[i] { + continue + } + + // z4 = g4 + x[i].C1.B1.Mul(&t0[i], &t1[i]) + + // t1 = g2 * g1 + t1[i].Mul(&x[i].C0.B2, &x[i].C0.B1) + // t2 = 2 * g4^2 - 3 * g2 * g1 + t2[i].Square(&x[i].C1.B1) + t2[i].Sub(&t2[i], &t1[i]) + t2[i].Double(&t2[i]) + t2[i].Sub(&t2[i], &t1[i]) + + // t1 = g3 * g5 (g3s can be 0s) + t1[i].Mul(&x[i].C1.B0, &x[i].C1.B2) + // z0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 + t2[i].Add(&t2[i], &t1[i]) + x[i].C0.B0.MulByNonResidue(&t2[i]). + Add(&x[i].C0.B0, &one) + } + + return x +} + +// Granger-Scott's cyclotomic square +// https://eprint.iacr.org/2009/565.pdf, 3.2 +func (z *E12) CyclotomicSquare(x *E12) *E12 { + + // x=(x0,x1,x2,x3,x4,x5,x6,x7) in E2^6 + // cyclosquare(x)=(3*x4^2*u + 3*x0^2 - 2*x0, + // 3*x2^2*u + 3*x3^2 - 2*x1, + // 3*x5^2*u + 3*x1^2 - 2*x2, + // 6*x1*x5*u + 2*x3, + // 6*x0*x4 + 2*x4, + // 6*x2*x3 + 2*x5) + + var t [9]E2 + + t[0].Square(&x.C1.B1) + t[1].Square(&x.C0.B0) + t[6].Add(&x.C1.B1, &x.C0.B0).Square(&t[6]).Sub(&t[6], &t[0]).Sub(&t[6], &t[1]) // 2*x4*x0 + t[2].Square(&x.C0.B2) + t[3].Square(&x.C1.B0) + t[7].Add(&x.C0.B2, &x.C1.B0).Square(&t[7]).Sub(&t[7], &t[2]).Sub(&t[7], &t[3]) // 2*x2*x3 + t[4].Square(&x.C1.B2) + t[5].Square(&x.C0.B1) + t[8].Add(&x.C1.B2, &x.C0.B1).Square(&t[8]).Sub(&t[8], &t[4]).Sub(&t[8], &t[5]).MulByNonResidue(&t[8]) // 2*x5*x1*u + + t[0].MulByNonResidue(&t[0]).Add(&t[0], &t[1]) // x4^2*u + x0^2 + t[2].MulByNonResidue(&t[2]).Add(&t[2], &t[3]) // x2^2*u + x3^2 + t[4].MulByNonResidue(&t[4]).Add(&t[4], &t[5]) // x5^2*u + x1^2 + + z.C0.B0.Sub(&t[0], &x.C0.B0).Double(&z.C0.B0).Add(&z.C0.B0, &t[0]) + z.C0.B1.Sub(&t[2], &x.C0.B1).Double(&z.C0.B1).Add(&z.C0.B1, &t[2]) + z.C0.B2.Sub(&t[4], &x.C0.B2).Double(&z.C0.B2).Add(&z.C0.B2, &t[4]) + + z.C1.B0.Add(&t[8], &x.C1.B0).Double(&z.C1.B0).Add(&z.C1.B0, &t[8]) + z.C1.B1.Add(&t[6], &x.C1.B1).Double(&z.C1.B1).Add(&z.C1.B1, &t[6]) + z.C1.B2.Add(&t[7], &x.C1.B2).Double(&z.C1.B2).Add(&z.C1.B2, &t[7]) + + return z +} + +// Inverse set z to the inverse of x in E12 and return z +// +// if x == 0, sets and returns z = x +func (z *E12) Inverse(x *E12) *E12 { + // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf + + var t0, t1, tmp E6 + t0.Square(&x.C0) + t1.Square(&x.C1) + tmp.MulByNonResidue(&t1) + t0.Sub(&t0, &tmp) + t1.Inverse(&t0) + z.C0.Mul(&x.C0, &t1) + z.C1.Mul(&x.C1, &t1).Neg(&z.C1) + + return z +} + +// BatchInvertE12 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE12(a []E12) []E12 { + res := make([]E12, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E12 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +// Exp sets z=xᵏ (mod q¹²) and returns it +// uses 2-bits windowed method +func (z *E12) Exp(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var res E12 + var ops [3]E12 + + res.SetOne() + ops[0].Set(&x) + ops[1].Square(&ops[0]) + ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1]) + + b := e.Bytes() + for i := range b { + w := b[i] + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.Square(&res).Square(&res) + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.Mul(&res, &ops[c-1]) + } + mask = mask >> 2 + } + } + z.Set(&res) + + return z +} + +// CyclotomicExp sets z=xᵏ (mod q¹²) and returns it +// uses 2-NAF decomposition +// x must be in the cyclotomic subgroup +// TODO: use a windowed method +func (z *E12) CyclotomicExp(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert (=conjugate) + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Conjugate(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var res, xInv E12 + xInv.InverseUnitary(&x) + res.SetOne() + eNAF := make([]int8, e.BitLen()+3) + n := ecc.NafDecomposition(e, eNAF[:]) + for i := n - 1; i >= 0; i-- { + res.CyclotomicSquare(&res) + if eNAF[i] == 1 { + res.Mul(&res, &x) + } else if eNAF[i] == -1 { + res.Mul(&res, &xInv) + } + } + z.Set(&res) + return z +} + +// ExpGLV sets z=xᵏ (q¹²) and returns it +// uses 2-dimensional GLV with 2-bits windowed method +// x must be in GT +// TODO: use 2-NAF +// TODO: use higher dimensional decomposition +func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert (=conjugate) + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Conjugate(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var table [15]E12 + var res E12 + var s1, s2 fr.Element + + res.SetOne() + + // table[b3b2b1b0-1] = b3b2*Frobinius(x) + b1b0*x + table[0].Set(&x) + table[3].Frobenius(&x) + + // split the scalar, modifies ±x, Frob(x) accordingly + s := ecc.SplitScalar(e, &glvBasis) + + if s[0].Sign() == -1 { + s[0].Neg(&s[0]) + table[0].InverseUnitary(&table[0]) + } + if s[1].Sign() == -1 { + s[1].Neg(&s[1]) + table[3].InverseUnitary(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2*Frobenius(x) + b1b0*x if b3b2b1b0 != 0 + table[1].CyclotomicSquare(&table[0]) + table[2].Mul(&table[1], &table[0]) + table[4].Mul(&table[3], &table[0]) + table[5].Mul(&table[3], &table[1]) + table[6].Mul(&table[3], &table[2]) + table[7].CyclotomicSquare(&table[3]) + table[8].Mul(&table[7], &table[0]) + table[9].Mul(&table[7], &table[1]) + table[10].Mul(&table[7], &table[2]) + table[11].Mul(&table[7], &table[3]) + table[12].Mul(&table[11], &table[0]) + table[13].Mul(&table[11], &table[1]) + table[14].Mul(&table[11], &table[2]) + + // bounds on the lattice base vectors guarantee that s1, s2 are len(r)/2 bits long max + s1 = s1.SetBigInt(&s[0]).Bits() + s2 = s2.SetBigInt(&s[1]).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(s1)/2 due to the bounds + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.CyclotomicSquare(&res).CyclotomicSquare(&res) + b1 := (s1[i] & mask) >> (62 - 2*j) + b2 := (s2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.Mul(&res, &table[s-1]) + } + mask = mask >> 2 + } + } + + z.Set(&res) + return z +} + +// InverseUnitary inverse a unitary element +func (z *E12) InverseUnitary(x *E12) *E12 { + return z.Conjugate(x) +} + +// Conjugate set z to x conjugated and return z +func (z *E12) Conjugate(x *E12) *E12 { + *z = *x + z.C1.Neg(&z.C1) + return z +} + +// SizeOfGT represents the size in bytes that a GT element need in binary form +const SizeOfGT = 48 * 12 + +// Marshal converts z to a byte slice +func (z *E12) Marshal() []byte { + b := z.Bytes() + return b[:] +} + +// Unmarshal is an alias to SetBytes() +func (z *E12) Unmarshal(buf []byte) error { + return z.SetBytes(buf) +} + +// Bytes returns the regular (non montgomery) value +// of z as a big-endian byte array. +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +func (z *E12) Bytes() (r [SizeOfGT]byte) { + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[528:528+fp.Bytes]), z.C0.B0.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[480:480+fp.Bytes]), z.C0.B0.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[432:432+fp.Bytes]), z.C0.B1.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[384:384+fp.Bytes]), z.C0.B1.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[336:336+fp.Bytes]), z.C0.B2.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[288:288+fp.Bytes]), z.C0.B2.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[240:240+fp.Bytes]), z.C1.B0.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[192:192+fp.Bytes]), z.C1.B0.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[144:144+fp.Bytes]), z.C1.B1.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[96:96+fp.Bytes]), z.C1.B1.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[48:48+fp.Bytes]), z.C1.B2.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[0:0+fp.Bytes]), z.C1.B2.A1) + + return +} + +// SetBytes interprets e as the bytes of a big-endian GT +// sets z to that value (in Montgomery form), and returns z. +// size(e) == 48 * 12 +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +func (z *E12) SetBytes(e []byte) error { + if len(e) != SizeOfGT { + return errors.New("invalid buffer size") + } + if err := z.C0.B0.A0.SetBytesCanonical(e[528 : 528+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B0.A1.SetBytesCanonical(e[480 : 480+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B1.A0.SetBytesCanonical(e[432 : 432+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B1.A1.SetBytesCanonical(e[384 : 384+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B2.A0.SetBytesCanonical(e[336 : 336+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B2.A1.SetBytesCanonical(e[288 : 288+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B0.A0.SetBytesCanonical(e[240 : 240+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B0.A1.SetBytesCanonical(e[192 : 192+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B1.A0.SetBytesCanonical(e[144 : 144+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B1.A1.SetBytesCanonical(e[96 : 96+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B2.A0.SetBytesCanonical(e[48 : 48+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B2.A1.SetBytesCanonical(e[0 : 0+fp.Bytes]); err != nil { + return err + } + + return nil +} + +// IsInSubGroup ensures GT/E12 is in correct subgroup +func (z *E12) IsInSubGroup() bool { + var a, b E12 + + // check z^(phi_k(p)) == 1 + a.FrobeniusSquare(z) + b.FrobeniusSquare(&a).Mul(&b, z) + + if !a.Equal(&b) { + return false + } + + // check z^(p+1-t) == 1 + a.Frobenius(z) + b.Expt(z) + + return a.Equal(&b) +} + +// CompressTorus GT/E12 element to half its size +// z must be in the cyclotomic subgroup +// i.e. z^(p^4-p^2+1)=1 +// e.g. GT +// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG +// z.C1 == 0 only when z \in {-1,1} +func (z *E12) CompressTorus() (E6, error) { + + if z.C1.IsZero() { + return E6{}, errors.New("invalid input") + } + + var res, tmp, one E6 + one.SetOne() + tmp.Inverse(&z.C1) + res.Add(&z.C0, &one). + Mul(&res, &tmp) + + return res, nil +} + +// BatchCompressTorus GT/E12 elements to half their size using a batch inversion. +// +// if len(x) == 0 or if any of the x[i].C1 coordinate is 0, this function returns an error. +func BatchCompressTorus(x []E12) ([]E6, error) { + + n := len(x) + if n == 0 { + return nil, errors.New("invalid input size") + } + + var one E6 + one.SetOne() + res := make([]E6, n) + + for i := 0; i < n; i++ { + res[i].Set(&x[i].C1) + // throw an error if any of the x[i].C1 is 0 + if res[i].IsZero() { + return nil, errors.New("invalid input; C1 is 0") + } + } + + t := BatchInvertE6(res) // costs 1 inverse + + for i := 0; i < n; i++ { + res[i].Add(&x[i].C0, &one). + Mul(&res[i], &t[i]) + } + + return res, nil +} + +// DecompressTorus GT/E12 a compressed element +// element must be in the cyclotomic subgroup +// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG +func (z *E6) DecompressTorus() E12 { + + var res, num, denum E12 + num.C0.Set(z) + num.C1.SetOne() + denum.C0.Set(z) + denum.C1.SetOne().Neg(&denum.C1) + res.Inverse(&denum). + Mul(&res, &num) + + return res +} + +// BatchDecompressTorus GT/E12 compressed elements +// using a batch inversion +func BatchDecompressTorus(x []E6) ([]E12, error) { + + n := len(x) + if n == 0 { + return []E12{}, errors.New("invalid input size") + } + + res := make([]E12, n) + num := make([]E12, n) + denum := make([]E12, n) + + for i := 0; i < n; i++ { + num[i].C0.Set(&x[i]) + num[i].C1.SetOne() + denum[i].C0.Set(&x[i]) + denum[i].C1.SetOne().Neg(&denum[i].C1) + } + + denum = BatchInvertE12(denum) // costs 1 inverse + + for i := 0; i < n; i++ { + res[i].Mul(&num[i], &denum[i]) + } + + return res, nil +} + +func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.C0.Select(cond, &caseZ.C0, &caseNz.C0) + z.C1.Select(cond, &caseZ.C1, &caseNz.C1) + + return z +} + +func (z *E12) Div(x *E12, y *E12) *E12 { + var r E12 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12_pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12_pairing.go new file mode 100644 index 00000000000..880520f815f --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12_pairing.go @@ -0,0 +1,117 @@ +package fptower + +func (z *E12) nSquare(n int) { + for i := 0; i < n; i++ { + z.CyclotomicSquare(z) + } +} + +func (z *E12) nSquareCompressed(n int) { + for i := 0; i < n; i++ { + z.CyclotomicSquareCompressed(z) + } +} + +// ExptHalf set z to x^(t/2) in E12 and return z +// const t/2 uint64 = 7566188111470821376 // negative +func (z *E12) ExptHalf(x *E12) *E12 { + var result E12 + var t [2]E12 + result.Set(x) + result.nSquareCompressed(15) + t[0].Set(&result) + result.nSquareCompressed(32) + t[1].Set(&result) + batch := BatchDecompressKarabina([]E12{t[0], t[1]}) + result.Mul(&batch[0], &batch[1]) + batch[1].nSquare(9) + result.Mul(&result, &batch[1]) + batch[1].nSquare(3) + result.Mul(&result, &batch[1]) + batch[1].nSquare(2) + result.Mul(&result, &batch[1]) + batch[1].CyclotomicSquare(&batch[1]) + result.Mul(&result, &batch[1]) + return z.Conjugate(&result) // because tAbsVal is negative +} + +// Expt set z to xᵗ in E12 and return z +// const t uint64 = 15132376222941642752 // negative +func (z *E12) Expt(x *E12) *E12 { + var result E12 + result.ExptHalf(x) + return z.CyclotomicSquare(&result) +} + +// MulBy014 multiplication by sparse element (c0, c1, 0, 0, c4) +func (z *E12) MulBy014(c0, c1, c4 *E2) *E12 { + + var a, b E6 + var d E2 + + a.Set(&z.C0) + a.MulBy01(c0, c1) + + b.Set(&z.C1) + b.MulBy1(c4) + d.Add(c1, c4) + + z.C1.Add(&z.C1, &z.C0) + z.C1.MulBy01(c0, &d) + z.C1.Sub(&z.C1, &a) + z.C1.Sub(&z.C1, &b) + z.C0.MulByNonResidue(&b) + z.C0.Add(&z.C0, &a) + + return z +} + +// Mul014By014 multiplication of sparse element (c0,c1,0,0,c4,0) by sparse element (d0,d1,0,0,d4,0) +func Mul014By014(d0, d1, d4, c0, c1, c4 *E2) [5]E2 { + var z00, tmp, x0, x1, x4, x04, x01, x14 E2 + x0.Mul(c0, d0) + x1.Mul(c1, d1) + x4.Mul(c4, d4) + tmp.Add(c0, c4) + x04.Add(d0, d4). + Mul(&x04, &tmp). + Sub(&x04, &x0). + Sub(&x04, &x4) + tmp.Add(c0, c1) + x01.Add(d0, d1). + Mul(&x01, &tmp). + Sub(&x01, &x0). + Sub(&x01, &x1) + tmp.Add(c1, c4) + x14.Add(d1, d4). + Mul(&x14, &tmp). + Sub(&x14, &x1). + Sub(&x14, &x4) + + z00.MulByNonResidue(&x4). + Add(&z00, &x0) + + return [5]E2{z00, x01, x1, x04, x14} +} + +// MulBy01245 multiplies z by an E12 sparse element of the form (x0, x1, x2, 0, x4, x5) +func (z *E12) MulBy01245(x *[5]E2) *E12 { + var c1, a, b, c, z0, z1 E6 + c0 := &E6{B0: x[0], B1: x[1], B2: x[2]} + c1.B1 = x[3] + c1.B2 = x[4] + a.Add(&z.C0, &z.C1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.C0, c0) + c.Set(&z.C1).MulBy12(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.C0 = z0 + z.C1 = z1 + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2.go new file mode 100644 index 00000000000..0390e7e4b34 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2.go @@ -0,0 +1,295 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "math/big" +) + +// E2 is a degree two finite field extension of fp.Element +type E2 struct { + A0, A1 fp.Element +} + +// Equal returns true if z equals x, false otherwise +func (z *E2) Equal(x *E2) bool { + return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) +} + +// Bits +// TODO @gbotrel fixme this shouldn't return a E2 +func (z *E2) Bits() E2 { + r := E2{} + r.A0 = z.A0.Bits() + r.A1 = z.A1.Bits() + return r +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +func (z *E2) Cmp(x *E2) int { + if a1 := z.A1.Cmp(&x.A1); a1 != 0 { + return a1 + } + return z.A0.Cmp(&x.A0) +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *E2) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + if z.A1.IsZero() { + return z.A0.LexicographicallyLargest() + } + return z.A1.LexicographicallyLargest() +} + +// SetString sets a E2 element from strings +func (z *E2) SetString(s1, s2 string) *E2 { + z.A0.SetString(s1) + z.A1.SetString(s2) + return z +} + +// SetZero sets an E2 elmt to zero +func (z *E2) SetZero() *E2 { + z.A0.SetZero() + z.A1.SetZero() + return z +} + +// Set sets an E2 from x +func (z *E2) Set(x *E2) *E2 { + z.A0 = x.A0 + z.A1 = x.A1 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E2) SetOne() *E2 { + z.A0.SetOne() + z.A1.SetZero() + return z +} + +// SetRandom sets a0 and a1 to random values +func (z *E2) SetRandom() (*E2, error) { + if _, err := z.A0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.A1.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if the two elements are equal, false otherwise +func (z *E2) IsZero() bool { + return z.A0.IsZero() && z.A1.IsZero() +} + +func (z *E2) IsOne() bool { + return z.A0.IsOne() && z.A1.IsZero() +} + +// Add adds two elements of E2 +func (z *E2) Add(x, y *E2) *E2 { + addE2(z, x, y) + return z +} + +// Sub two elements of E2 +func (z *E2) Sub(x, y *E2) *E2 { + subE2(z, x, y) + return z +} + +// Double doubles an E2 element +func (z *E2) Double(x *E2) *E2 { + doubleE2(z, x) + return z +} + +// Neg negates an E2 element +func (z *E2) Neg(x *E2) *E2 { + negE2(z, x) + return z +} + +// String implements Stringer interface for fancy printing +func (z *E2) String() string { + return z.A0.String() + "+" + z.A1.String() + "*u" +} + +// MulByElement multiplies an element in E2 by an element in fp +func (z *E2) MulByElement(x *E2, y *fp.Element) *E2 { + var yCopy fp.Element + yCopy.Set(y) + z.A0.Mul(&x.A0, &yCopy) + z.A1.Mul(&x.A1, &yCopy) + return z +} + +// Conjugate conjugates an element in E2 +func (z *E2) Conjugate(x *E2) *E2 { + z.A0 = x.A0 + z.A1.Neg(&x.A1) + return z +} + +// Halve sets z = z / 2 +func (z *E2) Halve() { + z.A0.Halve() + z.A1.Halve() +} + +// Legendre returns the Legendre symbol of z +func (z *E2) Legendre() int { + var n fp.Element + z.norm(&n) + return n.Legendre() +} + +// Exp sets z=xᵏ (mod q²) and returns it +func (z *E2) Exp(x E2, k *big.Int) *E2 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q²) == (x⁻¹)ᵏ (mod q²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + z.SetOne() + b := e.Bytes() + for i := 0; i < len(b); i++ { + w := b[i] + for j := 0; j < 8; j++ { + z.Square(z) + if (w & (0b10000000 >> j)) != 0 { + z.Mul(z, &x) + } + } + } + + return z +} + +func init() { + q := fp.Modulus() + tmp := big.NewInt(3) + sqrtExp1.Set(q).Sub(&sqrtExp1, tmp).Rsh(&sqrtExp1, 2) + + tmp.SetUint64(1) + sqrtExp2.Set(q).Sub(&sqrtExp2, tmp).Rsh(&sqrtExp2, 1) +} + +var sqrtExp1, sqrtExp2 big.Int + +// Sqrt sets z to the square root of and returns z +// The function does not test whether the square root +// exists or not, it's up to the caller to call +// Legendre beforehand. +// cf https://eprint.iacr.org/2012/685.pdf (algo 9) +func (z *E2) Sqrt(x *E2) *E2 { + + var a1, alpha, b, x0, minusone E2 + + minusone.SetOne().Neg(&minusone) + + a1.Exp(*x, &sqrtExp1) + alpha.Square(&a1). + Mul(&alpha, x) + x0.Mul(x, &a1) + if alpha.Equal(&minusone) { + var c fp.Element + c.Set(&x0.A0) + z.A0.Neg(&x0.A1) + z.A1.Set(&c) + return z + } + a1.SetOne() + b.Add(&a1, &alpha) + + b.Exp(b, &sqrtExp2).Mul(&x0, &b) + z.Set(&b) + return z +} + +// BatchInvertE2 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE2(a []E2) []E2 { + res := make([]E2, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E2 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.A0.Select(cond, &caseZ.A0, &caseNz.A0) + z.A1.Select(cond, &caseZ.A1, &caseNz.A1) + + return z +} + +func (z *E2) Div(x *E2, y *E2) *E2 { + var r E2 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.go new file mode 100644 index 00000000000..5121f7cca2b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.go @@ -0,0 +1,56 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +//go:noescape +func addE2(res, x, y *E2) + +//go:noescape +func subE2(res, x, y *E2) + +//go:noescape +func doubleE2(res, x *E2) + +//go:noescape +func negE2(res, x *E2) + +//go:noescape +func mulNonResE2(res, x *E2) + +//go:noescape +func squareAdxE2(res, x *E2) + +//go:noescape +func mulAdxE2(z, x, y *E2) + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { + mulAdxE2(z, x, y) + return z +} + +// MulByNonResidue multiplies a E2 by (1,1) +func (z *E2) MulByNonResidue(x *E2) *E2 { + mulNonResE2(z, x) + return z +} + +// Square sets z to the E2-product of x,x, returns z +func (z *E2) Square(x *E2) *E2 { + squareAdxE2(z, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.s new file mode 100644 index 00000000000..7fc53f46338 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_amd64.s @@ -0,0 +1,3191 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "textflag.h" +#include "funcdata.h" + +// modulus q +DATA q<>+0(SB)/8, $0xb9feffffffffaaab +DATA q<>+8(SB)/8, $0x1eabfffeb153ffff +DATA q<>+16(SB)/8, $0x6730d2a0f6b0f624 +DATA q<>+24(SB)/8, $0x64774b84f38512bf +DATA q<>+32(SB)/8, $0x4b1ba7b6434bacd7 +DATA q<>+40(SB)/8, $0x1a0111ea397fe69a +GLOBL q<>(SB), (RODATA+NOPTR), $48 + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, $0x89f3fffcfffcfffd +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE(ra0, ra1, ra2, ra3, ra4, ra5, rb0, rb1, rb2, rb3, rb4, rb5) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + MOVQ ra1, rb1; \ + SBBQ q<>+8(SB), ra1; \ + MOVQ ra2, rb2; \ + SBBQ q<>+16(SB), ra2; \ + MOVQ ra3, rb3; \ + SBBQ q<>+24(SB), ra3; \ + MOVQ ra4, rb4; \ + SBBQ q<>+32(SB), ra4; \ + MOVQ ra5, rb5; \ + SBBQ q<>+40(SB), ra5; \ + CMOVQCS rb0, ra0; \ + CMOVQCS rb1, ra1; \ + CMOVQCS rb2, ra2; \ + CMOVQCS rb3, ra3; \ + CMOVQCS rb4, ra4; \ + CMOVQCS rb5, ra5; \ + +TEXT ·addE2(SB), NOSPLIT, $0-24 + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ 32(AX), R9 + MOVQ 40(AX), R10 + MOVQ y+16(FP), DX + ADDQ 0(DX), BX + ADCQ 8(DX), SI + ADCQ 16(DX), DI + ADCQ 24(DX), R8 + ADCQ 32(DX), R9 + ADCQ 40(DX), R10 + + // reduce element(BX,SI,DI,R8,R9,R10) using temp registers (R11,R12,R13,R14,R15,s0-8(SP)) + REDUCE(BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15,s0-8(SP)) + + MOVQ res+0(FP), CX + MOVQ BX, 0(CX) + MOVQ SI, 8(CX) + MOVQ DI, 16(CX) + MOVQ R8, 24(CX) + MOVQ R9, 32(CX) + MOVQ R10, 40(CX) + MOVQ 48(AX), BX + MOVQ 56(AX), SI + MOVQ 64(AX), DI + MOVQ 72(AX), R8 + MOVQ 80(AX), R9 + MOVQ 88(AX), R10 + ADDQ 48(DX), BX + ADCQ 56(DX), SI + ADCQ 64(DX), DI + ADCQ 72(DX), R8 + ADCQ 80(DX), R9 + ADCQ 88(DX), R10 + + // reduce element(BX,SI,DI,R8,R9,R10) using temp registers (R11,R12,R13,R14,R15,s0-8(SP)) + REDUCE(BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15,s0-8(SP)) + + MOVQ BX, 48(CX) + MOVQ SI, 56(CX) + MOVQ DI, 64(CX) + MOVQ R8, 72(CX) + MOVQ R9, 80(CX) + MOVQ R10, 88(CX) + RET + +TEXT ·doubleE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), CX + MOVQ 8(AX), BX + MOVQ 16(AX), SI + MOVQ 24(AX), DI + MOVQ 32(AX), R8 + MOVQ 40(AX), R9 + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + ADCQ R9, R9 + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ CX, 0(DX) + MOVQ BX, 8(DX) + MOVQ SI, 16(DX) + MOVQ DI, 24(DX) + MOVQ R8, 32(DX) + MOVQ R9, 40(DX) + MOVQ 48(AX), CX + MOVQ 56(AX), BX + MOVQ 64(AX), SI + MOVQ 72(AX), DI + MOVQ 80(AX), R8 + MOVQ 88(AX), R9 + ADDQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + ADCQ R8, R8 + ADCQ R9, R9 + + // reduce element(CX,BX,SI,DI,R8,R9) using temp registers (R10,R11,R12,R13,R14,R15) + REDUCE(CX,BX,SI,DI,R8,R9,R10,R11,R12,R13,R14,R15) + + MOVQ CX, 48(DX) + MOVQ BX, 56(DX) + MOVQ SI, 64(DX) + MOVQ DI, 72(DX) + MOVQ R8, 80(DX) + MOVQ R9, 88(DX) + RET + +TEXT ·subE2(SB), NOSPLIT, $0-24 + XORQ R9, R9 + MOVQ x+8(FP), R8 + MOVQ 0(R8), AX + MOVQ 8(R8), DX + MOVQ 16(R8), CX + MOVQ 24(R8), BX + MOVQ 32(R8), SI + MOVQ 40(R8), DI + MOVQ y+16(FP), R8 + SUBQ 0(R8), AX + SBBQ 8(R8), DX + SBBQ 16(R8), CX + SBBQ 24(R8), BX + SBBQ 32(R8), SI + SBBQ 40(R8), DI + MOVQ x+8(FP), R8 + MOVQ $0xb9feffffffffaaab, R10 + MOVQ $0x1eabfffeb153ffff, R11 + MOVQ $0x6730d2a0f6b0f624, R12 + MOVQ $0x64774b84f38512bf, R13 + MOVQ $0x4b1ba7b6434bacd7, R14 + MOVQ $0x1a0111ea397fe69a, R15 + CMOVQCC R9, R10 + CMOVQCC R9, R11 + CMOVQCC R9, R12 + CMOVQCC R9, R13 + CMOVQCC R9, R14 + CMOVQCC R9, R15 + ADDQ R10, AX + ADCQ R11, DX + ADCQ R12, CX + ADCQ R13, BX + ADCQ R14, SI + ADCQ R15, DI + MOVQ res+0(FP), R10 + MOVQ AX, 0(R10) + MOVQ DX, 8(R10) + MOVQ CX, 16(R10) + MOVQ BX, 24(R10) + MOVQ SI, 32(R10) + MOVQ DI, 40(R10) + MOVQ 48(R8), AX + MOVQ 56(R8), DX + MOVQ 64(R8), CX + MOVQ 72(R8), BX + MOVQ 80(R8), SI + MOVQ 88(R8), DI + MOVQ y+16(FP), R8 + SUBQ 48(R8), AX + SBBQ 56(R8), DX + SBBQ 64(R8), CX + SBBQ 72(R8), BX + SBBQ 80(R8), SI + SBBQ 88(R8), DI + MOVQ $0xb9feffffffffaaab, R11 + MOVQ $0x1eabfffeb153ffff, R12 + MOVQ $0x6730d2a0f6b0f624, R13 + MOVQ $0x64774b84f38512bf, R14 + MOVQ $0x4b1ba7b6434bacd7, R15 + MOVQ $0x1a0111ea397fe69a, R10 + CMOVQCC R9, R11 + CMOVQCC R9, R12 + CMOVQCC R9, R13 + CMOVQCC R9, R14 + CMOVQCC R9, R15 + CMOVQCC R9, R10 + ADDQ R11, AX + ADCQ R12, DX + ADCQ R13, CX + ADCQ R14, BX + ADCQ R15, SI + ADCQ R10, DI + MOVQ res+0(FP), R8 + MOVQ AX, 48(R8) + MOVQ DX, 56(R8) + MOVQ CX, 64(R8) + MOVQ BX, 72(R8) + MOVQ SI, 80(R8) + MOVQ DI, 88(R8) + RET + +TEXT ·negE2(SB), NOSPLIT, $0-16 + MOVQ res+0(FP), DX + MOVQ x+8(FP), AX + MOVQ 0(AX), BX + MOVQ 8(AX), SI + MOVQ 16(AX), DI + MOVQ 24(AX), R8 + MOVQ 32(AX), R9 + MOVQ 40(AX), R10 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + ORQ R9, AX + ORQ R10, AX + TESTQ AX, AX + JNE l1 + MOVQ AX, 0(DX) + MOVQ AX, 8(DX) + MOVQ AX, 16(DX) + MOVQ AX, 24(DX) + MOVQ AX, 32(DX) + MOVQ AX, 40(DX) + JMP l3 + +l1: + MOVQ $0xb9feffffffffaaab, CX + SUBQ BX, CX + MOVQ CX, 0(DX) + MOVQ $0x1eabfffeb153ffff, CX + SBBQ SI, CX + MOVQ CX, 8(DX) + MOVQ $0x6730d2a0f6b0f624, CX + SBBQ DI, CX + MOVQ CX, 16(DX) + MOVQ $0x64774b84f38512bf, CX + SBBQ R8, CX + MOVQ CX, 24(DX) + MOVQ $0x4b1ba7b6434bacd7, CX + SBBQ R9, CX + MOVQ CX, 32(DX) + MOVQ $0x1a0111ea397fe69a, CX + SBBQ R10, CX + MOVQ CX, 40(DX) + +l3: + MOVQ x+8(FP), AX + MOVQ 48(AX), BX + MOVQ 56(AX), SI + MOVQ 64(AX), DI + MOVQ 72(AX), R8 + MOVQ 80(AX), R9 + MOVQ 88(AX), R10 + MOVQ BX, AX + ORQ SI, AX + ORQ DI, AX + ORQ R8, AX + ORQ R9, AX + ORQ R10, AX + TESTQ AX, AX + JNE l2 + MOVQ AX, 48(DX) + MOVQ AX, 56(DX) + MOVQ AX, 64(DX) + MOVQ AX, 72(DX) + MOVQ AX, 80(DX) + MOVQ AX, 88(DX) + RET + +l2: + MOVQ $0xb9feffffffffaaab, CX + SUBQ BX, CX + MOVQ CX, 48(DX) + MOVQ $0x1eabfffeb153ffff, CX + SBBQ SI, CX + MOVQ CX, 56(DX) + MOVQ $0x6730d2a0f6b0f624, CX + SBBQ DI, CX + MOVQ CX, 64(DX) + MOVQ $0x64774b84f38512bf, CX + SBBQ R8, CX + MOVQ CX, 72(DX) + MOVQ $0x4b1ba7b6434bacd7, CX + SBBQ R9, CX + MOVQ CX, 80(DX) + MOVQ $0x1a0111ea397fe69a, CX + SBBQ R10, CX + MOVQ CX, 88(DX) + RET + +TEXT ·mulNonResE2(SB), NOSPLIT, $0-16 + XORQ R15, R15 + MOVQ x+8(FP), R14 + MOVQ 0(R14), AX + MOVQ 8(R14), DX + MOVQ 16(R14), CX + MOVQ 24(R14), BX + MOVQ 32(R14), SI + MOVQ 40(R14), DI + SUBQ 48(R14), AX + SBBQ 56(R14), DX + SBBQ 64(R14), CX + SBBQ 72(R14), BX + SBBQ 80(R14), SI + SBBQ 88(R14), DI + MOVQ $0xb9feffffffffaaab, R8 + MOVQ $0x1eabfffeb153ffff, R9 + MOVQ $0x6730d2a0f6b0f624, R10 + MOVQ $0x64774b84f38512bf, R11 + MOVQ $0x4b1ba7b6434bacd7, R12 + MOVQ $0x1a0111ea397fe69a, R13 + CMOVQCC R15, R8 + CMOVQCC R15, R9 + CMOVQCC R15, R10 + CMOVQCC R15, R11 + CMOVQCC R15, R12 + CMOVQCC R15, R13 + ADDQ R8, AX + ADCQ R9, DX + ADCQ R10, CX + ADCQ R11, BX + ADCQ R12, SI + ADCQ R13, DI + MOVQ 48(R14), R8 + MOVQ 56(R14), R9 + MOVQ 64(R14), R10 + MOVQ 72(R14), R11 + MOVQ 80(R14), R12 + MOVQ 88(R14), R13 + ADDQ 0(R14), R8 + ADCQ 8(R14), R9 + ADCQ 16(R14), R10 + ADCQ 24(R14), R11 + ADCQ 32(R14), R12 + ADCQ 40(R14), R13 + MOVQ res+0(FP), R15 + MOVQ AX, 0(R15) + MOVQ DX, 8(R15) + MOVQ CX, 16(R15) + MOVQ BX, 24(R15) + MOVQ SI, 32(R15) + MOVQ DI, 40(R15) + + // reduce element(R8,R9,R10,R11,R12,R13) using temp registers (AX,DX,CX,BX,SI,DI) + REDUCE(R8,R9,R10,R11,R12,R13,AX,DX,CX,BX,SI,DI) + + MOVQ R8, 48(R15) + MOVQ R9, 56(R15) + MOVQ R10, 64(R15) + MOVQ R11, 72(R15) + MOVQ R12, 80(R15) + MOVQ R13, 88(R15) + RET + +TEXT ·squareAdxE2(SB), $48-16 + NO_LOCAL_POINTERS + + // z.A0 = (x.A0 + x.A1) * (x.A0 - x.A1) + // z.A1 = 2 * x.A0 * x.A1 + + CMPB ·supportAdx(SB), $1 + JNE l4 + + // 2 * x.A0 * x.A1 + MOVQ x+8(FP), AX + + // 2 * x.A1[0] -> R14 + // 2 * x.A1[1] -> R15 + // 2 * x.A1[2] -> CX + // 2 * x.A1[3] -> BX + // 2 * x.A1[4] -> SI + // 2 * x.A1[5] -> DI + MOVQ 48(AX), R14 + MOVQ 56(AX), R15 + MOVQ 64(AX), CX + MOVQ 72(AX), BX + MOVQ 80(AX), SI + MOVQ 88(AX), DI + ADDQ R14, R14 + ADCQ R15, R15 + ADCQ CX, CX + ADCQ BX, BX + ADCQ SI, SI + ADCQ DI, DI + + // A -> BP + // t[0] -> R8 + // t[1] -> R9 + // t[2] -> R10 + // t[3] -> R11 + // t[4] -> R12 + // t[5] -> R13 + // clear the flags + XORQ AX, AX + MOVQ x+8(FP), DX + MOVQ 0(DX), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R14, R8, R9 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R15, AX, R10 + ADOXQ AX, R9 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ CX, AX, R11 + ADOXQ AX, R10 + + // (A,t[3]) := x[3]*y[0] + A + MULXQ BX, AX, R12 + ADOXQ AX, R11 + + // (A,t[4]) := x[4]*y[0] + A + MULXQ SI, AX, R13 + ADOXQ AX, R12 + + // (A,t[5]) := x[5]*y[0] + A + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ x+8(FP), DX + MOVQ 8(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ x+8(FP), DX + MOVQ 16(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ x+8(FP), DX + MOVQ 24(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ x+8(FP), DX + MOVQ 32(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ x+8(FP), DX + MOVQ 40(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // reduce element(R8,R9,R10,R11,R12,R13) using temp registers (R14,R15,CX,BX,SI,DI) + REDUCE(R8,R9,R10,R11,R12,R13,R14,R15,CX,BX,SI,DI) + + MOVQ x+8(FP), AX + + // x.A1[0] -> R14 + // x.A1[1] -> R15 + // x.A1[2] -> CX + // x.A1[3] -> BX + // x.A1[4] -> SI + // x.A1[5] -> DI + MOVQ 48(AX), R14 + MOVQ 56(AX), R15 + MOVQ 64(AX), CX + MOVQ 72(AX), BX + MOVQ 80(AX), SI + MOVQ 88(AX), DI + MOVQ res+0(FP), DX + MOVQ R8, 48(DX) + MOVQ R9, 56(DX) + MOVQ R10, 64(DX) + MOVQ R11, 72(DX) + MOVQ R12, 80(DX) + MOVQ R13, 88(DX) + MOVQ R14, R8 + MOVQ R15, R9 + MOVQ CX, R10 + MOVQ BX, R11 + MOVQ SI, R12 + MOVQ DI, R13 + + // Add(&x.A0, &x.A1) + ADDQ 0(AX), R14 + ADCQ 8(AX), R15 + ADCQ 16(AX), CX + ADCQ 24(AX), BX + ADCQ 32(AX), SI + ADCQ 40(AX), DI + MOVQ R14, s0-8(SP) + MOVQ R15, s1-16(SP) + MOVQ CX, s2-24(SP) + MOVQ BX, s3-32(SP) + MOVQ SI, s4-40(SP) + MOVQ DI, s5-48(SP) + XORQ BP, BP + + // Sub(&x.A0, &x.A1) + MOVQ 0(AX), R14 + MOVQ 8(AX), R15 + MOVQ 16(AX), CX + MOVQ 24(AX), BX + MOVQ 32(AX), SI + MOVQ 40(AX), DI + SUBQ R8, R14 + SBBQ R9, R15 + SBBQ R10, CX + SBBQ R11, BX + SBBQ R12, SI + SBBQ R13, DI + MOVQ $0xb9feffffffffaaab, R8 + MOVQ $0x1eabfffeb153ffff, R9 + MOVQ $0x6730d2a0f6b0f624, R10 + MOVQ $0x64774b84f38512bf, R11 + MOVQ $0x4b1ba7b6434bacd7, R12 + MOVQ $0x1a0111ea397fe69a, R13 + CMOVQCC BP, R8 + CMOVQCC BP, R9 + CMOVQCC BP, R10 + CMOVQCC BP, R11 + CMOVQCC BP, R12 + CMOVQCC BP, R13 + ADDQ R8, R14 + ADCQ R9, R15 + ADCQ R10, CX + ADCQ R11, BX + ADCQ R12, SI + ADCQ R13, DI + + // A -> BP + // t[0] -> R8 + // t[1] -> R9 + // t[2] -> R10 + // t[3] -> R11 + // t[4] -> R12 + // t[5] -> R13 + // clear the flags + XORQ AX, AX + MOVQ s0-8(SP), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R14, R8, R9 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R15, AX, R10 + ADOXQ AX, R9 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ CX, AX, R11 + ADOXQ AX, R10 + + // (A,t[3]) := x[3]*y[0] + A + MULXQ BX, AX, R12 + ADOXQ AX, R11 + + // (A,t[4]) := x[4]*y[0] + A + MULXQ SI, AX, R13 + ADOXQ AX, R12 + + // (A,t[5]) := x[5]*y[0] + A + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s1-16(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s2-24(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s3-32(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s4-40(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s5-48(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // reduce element(R8,R9,R10,R11,R12,R13) using temp registers (R14,R15,CX,BX,SI,DI) + REDUCE(R8,R9,R10,R11,R12,R13,R14,R15,CX,BX,SI,DI) + + MOVQ res+0(FP), AX + MOVQ R8, 0(AX) + MOVQ R9, 8(AX) + MOVQ R10, 16(AX) + MOVQ R11, 24(AX) + MOVQ R12, 32(AX) + MOVQ R13, 40(AX) + RET + +l4: + MOVQ res+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + CALL ·squareGenericE2(SB) + RET + +TEXT ·mulAdxE2(SB), $96-24 + NO_LOCAL_POINTERS + + // var a, b, c fp.Element + // a.Add(&x.A0, &x.A1) + // b.Add(&y.A0, &y.A1) + // a.Mul(&a, &b) + // b.Mul(&x.A0, &y.A0) + // c.Mul(&x.A1, &y.A1) + // z.A1.Sub(&a, &b).Sub(&z.A1, &c) + // z.A0.Sub(&b, &c) + + CMPB ·supportAdx(SB), $1 + JNE l5 + MOVQ x+8(FP), AX + MOVQ 48(AX), R14 + MOVQ 56(AX), R15 + MOVQ 64(AX), CX + MOVQ 72(AX), BX + MOVQ 80(AX), SI + MOVQ 88(AX), DI + + // A -> BP + // t[0] -> R8 + // t[1] -> R9 + // t[2] -> R10 + // t[3] -> R11 + // t[4] -> R12 + // t[5] -> R13 + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 48(DX), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R14, R8, R9 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R15, AX, R10 + ADOXQ AX, R9 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ CX, AX, R11 + ADOXQ AX, R10 + + // (A,t[3]) := x[3]*y[0] + A + MULXQ BX, AX, R12 + ADOXQ AX, R11 + + // (A,t[4]) := x[4]*y[0] + A + MULXQ SI, AX, R13 + ADOXQ AX, R12 + + // (A,t[5]) := x[5]*y[0] + A + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 56(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 64(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 72(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 80(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 88(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // reduce element(R8,R9,R10,R11,R12,R13) using temp registers (R14,R15,CX,BX,SI,DI) + REDUCE(R8,R9,R10,R11,R12,R13,R14,R15,CX,BX,SI,DI) + + MOVQ R8, s6-56(SP) + MOVQ R9, s7-64(SP) + MOVQ R10, s8-72(SP) + MOVQ R11, s9-80(SP) + MOVQ R12, s10-88(SP) + MOVQ R13, s11-96(SP) + MOVQ x+8(FP), AX + MOVQ y+16(FP), DX + MOVQ 48(AX), R14 + MOVQ 56(AX), R15 + MOVQ 64(AX), CX + MOVQ 72(AX), BX + MOVQ 80(AX), SI + MOVQ 88(AX), DI + ADDQ 0(AX), R14 + ADCQ 8(AX), R15 + ADCQ 16(AX), CX + ADCQ 24(AX), BX + ADCQ 32(AX), SI + ADCQ 40(AX), DI + MOVQ R14, s0-8(SP) + MOVQ R15, s1-16(SP) + MOVQ CX, s2-24(SP) + MOVQ BX, s3-32(SP) + MOVQ SI, s4-40(SP) + MOVQ DI, s5-48(SP) + MOVQ 0(DX), R14 + MOVQ 8(DX), R15 + MOVQ 16(DX), CX + MOVQ 24(DX), BX + MOVQ 32(DX), SI + MOVQ 40(DX), DI + ADDQ 48(DX), R14 + ADCQ 56(DX), R15 + ADCQ 64(DX), CX + ADCQ 72(DX), BX + ADCQ 80(DX), SI + ADCQ 88(DX), DI + + // A -> BP + // t[0] -> R8 + // t[1] -> R9 + // t[2] -> R10 + // t[3] -> R11 + // t[4] -> R12 + // t[5] -> R13 + // clear the flags + XORQ AX, AX + MOVQ s0-8(SP), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R14, R8, R9 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R15, AX, R10 + ADOXQ AX, R9 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ CX, AX, R11 + ADOXQ AX, R10 + + // (A,t[3]) := x[3]*y[0] + A + MULXQ BX, AX, R12 + ADOXQ AX, R11 + + // (A,t[4]) := x[4]*y[0] + A + MULXQ SI, AX, R13 + ADOXQ AX, R12 + + // (A,t[5]) := x[5]*y[0] + A + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s1-16(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s2-24(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s3-32(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s4-40(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ s5-48(SP), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // reduce element(R8,R9,R10,R11,R12,R13) using temp registers (R14,R15,CX,BX,SI,DI) + REDUCE(R8,R9,R10,R11,R12,R13,R14,R15,CX,BX,SI,DI) + + MOVQ R8, s0-8(SP) + MOVQ R9, s1-16(SP) + MOVQ R10, s2-24(SP) + MOVQ R11, s3-32(SP) + MOVQ R12, s4-40(SP) + MOVQ R13, s5-48(SP) + MOVQ x+8(FP), AX + MOVQ 0(AX), R14 + MOVQ 8(AX), R15 + MOVQ 16(AX), CX + MOVQ 24(AX), BX + MOVQ 32(AX), SI + MOVQ 40(AX), DI + + // A -> BP + // t[0] -> R8 + // t[1] -> R9 + // t[2] -> R10 + // t[3] -> R11 + // t[4] -> R12 + // t[5] -> R13 + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 0(DX), DX + + // (A,t[0]) := x[0]*y[0] + A + MULXQ R14, R8, R9 + + // (A,t[1]) := x[1]*y[0] + A + MULXQ R15, AX, R10 + ADOXQ AX, R9 + + // (A,t[2]) := x[2]*y[0] + A + MULXQ CX, AX, R11 + ADOXQ AX, R10 + + // (A,t[3]) := x[3]*y[0] + A + MULXQ BX, AX, R12 + ADOXQ AX, R11 + + // (A,t[4]) := x[4]*y[0] + A + MULXQ SI, AX, R13 + ADOXQ AX, R12 + + // (A,t[5]) := x[5]*y[0] + A + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 8(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[1] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[1] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[1] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[1] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[1] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[1] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 16(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[2] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[2] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[2] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[2] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[2] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[2] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 24(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[3] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[3] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[3] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[3] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[3] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[3] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 32(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[4] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[4] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[4] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[4] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[4] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[4] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // clear the flags + XORQ AX, AX + MOVQ y+16(FP), DX + MOVQ 40(DX), DX + + // (A,t[0]) := t[0] + x[0]*y[5] + A + MULXQ R14, AX, BP + ADOXQ AX, R8 + + // (A,t[1]) := t[1] + x[1]*y[5] + A + ADCXQ BP, R9 + MULXQ R15, AX, BP + ADOXQ AX, R9 + + // (A,t[2]) := t[2] + x[2]*y[5] + A + ADCXQ BP, R10 + MULXQ CX, AX, BP + ADOXQ AX, R10 + + // (A,t[3]) := t[3] + x[3]*y[5] + A + ADCXQ BP, R11 + MULXQ BX, AX, BP + ADOXQ AX, R11 + + // (A,t[4]) := t[4] + x[4]*y[5] + A + ADCXQ BP, R12 + MULXQ SI, AX, BP + ADOXQ AX, R12 + + // (A,t[5]) := t[5] + x[5]*y[5] + A + ADCXQ BP, R13 + MULXQ DI, AX, BP + ADOXQ AX, R13 + + // A += carries from ADCXQ and ADOXQ + MOVQ $0, AX + ADCXQ AX, BP + ADOXQ AX, BP + PUSHQ BP + + // m := t[0]*q'[0] mod W + MOVQ qInv0<>(SB), DX + IMULQ R8, DX + + // clear the flags + XORQ AX, AX + + // C,_ := t[0] + m*q[0] + MULXQ q<>+0(SB), AX, BP + ADCXQ R8, AX + MOVQ BP, R8 + POPQ BP + + // (C,t[0]) := t[1] + m*q[1] + C + ADCXQ R9, R8 + MULXQ q<>+8(SB), AX, R9 + ADOXQ AX, R8 + + // (C,t[1]) := t[2] + m*q[2] + C + ADCXQ R10, R9 + MULXQ q<>+16(SB), AX, R10 + ADOXQ AX, R9 + + // (C,t[2]) := t[3] + m*q[3] + C + ADCXQ R11, R10 + MULXQ q<>+24(SB), AX, R11 + ADOXQ AX, R10 + + // (C,t[3]) := t[4] + m*q[4] + C + ADCXQ R12, R11 + MULXQ q<>+32(SB), AX, R12 + ADOXQ AX, R11 + + // (C,t[4]) := t[5] + m*q[5] + C + ADCXQ R13, R12 + MULXQ q<>+40(SB), AX, R13 + ADOXQ AX, R12 + + // t[5] = C + A + MOVQ $0, AX + ADCXQ AX, R13 + ADOXQ BP, R13 + + // reduce element(R8,R9,R10,R11,R12,R13) using temp registers (R14,R15,CX,BX,SI,DI) + REDUCE(R8,R9,R10,R11,R12,R13,R14,R15,CX,BX,SI,DI) + + XORQ DX, DX + MOVQ s0-8(SP), R14 + MOVQ s1-16(SP), R15 + MOVQ s2-24(SP), CX + MOVQ s3-32(SP), BX + MOVQ s4-40(SP), SI + MOVQ s5-48(SP), DI + SUBQ R8, R14 + SBBQ R9, R15 + SBBQ R10, CX + SBBQ R11, BX + SBBQ R12, SI + SBBQ R13, DI + MOVQ R8, s0-8(SP) + MOVQ R9, s1-16(SP) + MOVQ R10, s2-24(SP) + MOVQ R11, s3-32(SP) + MOVQ R12, s4-40(SP) + MOVQ R13, s5-48(SP) + MOVQ $0xb9feffffffffaaab, R8 + MOVQ $0x1eabfffeb153ffff, R9 + MOVQ $0x6730d2a0f6b0f624, R10 + MOVQ $0x64774b84f38512bf, R11 + MOVQ $0x4b1ba7b6434bacd7, R12 + MOVQ $0x1a0111ea397fe69a, R13 + CMOVQCC DX, R8 + CMOVQCC DX, R9 + CMOVQCC DX, R10 + CMOVQCC DX, R11 + CMOVQCC DX, R12 + CMOVQCC DX, R13 + ADDQ R8, R14 + ADCQ R9, R15 + ADCQ R10, CX + ADCQ R11, BX + ADCQ R12, SI + ADCQ R13, DI + SUBQ s6-56(SP), R14 + SBBQ s7-64(SP), R15 + SBBQ s8-72(SP), CX + SBBQ s9-80(SP), BX + SBBQ s10-88(SP), SI + SBBQ s11-96(SP), DI + MOVQ $0xb9feffffffffaaab, R8 + MOVQ $0x1eabfffeb153ffff, R9 + MOVQ $0x6730d2a0f6b0f624, R10 + MOVQ $0x64774b84f38512bf, R11 + MOVQ $0x4b1ba7b6434bacd7, R12 + MOVQ $0x1a0111ea397fe69a, R13 + CMOVQCC DX, R8 + CMOVQCC DX, R9 + CMOVQCC DX, R10 + CMOVQCC DX, R11 + CMOVQCC DX, R12 + CMOVQCC DX, R13 + ADDQ R8, R14 + ADCQ R9, R15 + ADCQ R10, CX + ADCQ R11, BX + ADCQ R12, SI + ADCQ R13, DI + MOVQ z+0(FP), AX + MOVQ R14, 48(AX) + MOVQ R15, 56(AX) + MOVQ CX, 64(AX) + MOVQ BX, 72(AX) + MOVQ SI, 80(AX) + MOVQ DI, 88(AX) + MOVQ s0-8(SP), R8 + MOVQ s1-16(SP), R9 + MOVQ s2-24(SP), R10 + MOVQ s3-32(SP), R11 + MOVQ s4-40(SP), R12 + MOVQ s5-48(SP), R13 + SUBQ s6-56(SP), R8 + SBBQ s7-64(SP), R9 + SBBQ s8-72(SP), R10 + SBBQ s9-80(SP), R11 + SBBQ s10-88(SP), R12 + SBBQ s11-96(SP), R13 + MOVQ $0xb9feffffffffaaab, R14 + MOVQ $0x1eabfffeb153ffff, R15 + MOVQ $0x6730d2a0f6b0f624, CX + MOVQ $0x64774b84f38512bf, BX + MOVQ $0x4b1ba7b6434bacd7, SI + MOVQ $0x1a0111ea397fe69a, DI + CMOVQCC DX, R14 + CMOVQCC DX, R15 + CMOVQCC DX, CX + CMOVQCC DX, BX + CMOVQCC DX, SI + CMOVQCC DX, DI + ADDQ R14, R8 + ADCQ R15, R9 + ADCQ CX, R10 + ADCQ BX, R11 + ADCQ SI, R12 + ADCQ DI, R13 + MOVQ R8, 0(AX) + MOVQ R9, 8(AX) + MOVQ R10, 16(AX) + MOVQ R11, 24(AX) + MOVQ R12, 32(AX) + MOVQ R13, 40(AX) + RET + +l5: + MOVQ z+0(FP), AX + MOVQ AX, (SP) + MOVQ x+8(FP), AX + MOVQ AX, 8(SP) + MOVQ y+16(FP), AX + MOVQ AX, 16(SP) + CALL ·mulGenericE2(SB) + RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381.go new file mode 100644 index 00000000000..32fb644b69c --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381.go @@ -0,0 +1,105 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + +// used with !amd64, make staticcheck happier. +var ( + _ = mulGenericE2 + _ = squareGenericE2 +) + +// mulGenericE2 sets z to the E2-product of x,y, returns z +// note: do not rename, this is referenced in the x86 assembly impl +func mulGenericE2(z, x, y *E2) { + var a, b, c fp.Element + a.Add(&x.A0, &x.A1) + b.Add(&y.A0, &y.A1) + a.Mul(&a, &b) + b.Mul(&x.A0, &y.A0) + c.Mul(&x.A1, &y.A1) + z.A1.Sub(&a, &b).Sub(&z.A1, &c) + z.A0.Sub(&b, &c) +} + +// Square sets z to the E2-product of x,x returns z +func squareGenericE2(z, x *E2) *E2 { + // adapted from algo 22 https://eprint.iacr.org/2010/354.pdf + var a, b fp.Element + a.Add(&x.A0, &x.A1) + b.Sub(&x.A0, &x.A1) + a.Mul(&a, &b) + b.Mul(&x.A0, &x.A1).Double(&b) + z.A0.Set(&a) + z.A1.Set(&b) + return z +} + +var twoInv = fp.Element{ + 1730508156817200468, + 9606178027640717313, + 7150789853162776431, + 7936136305760253186, + 15245073033536294050, + 1728177566264616342, +} + +// MulByNonResidueInv multiplies a E2 by (1,1)^{-1} +func (z *E2) MulByNonResidueInv(x *E2) *E2 { + + var tmp fp.Element + tmp.Add(&x.A0, &x.A1) + z.A1.Sub(&x.A1, &x.A0).Mul(&z.A1, &twoInv) + z.A0.Set(&tmp).Mul(&z.A0, &twoInv) + + return z +} + +// Inverse sets z to the E2-inverse of x, returns z +// +// if x == 0, sets and returns z = x +func (z *E2) Inverse(x *E2) *E2 { + // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf + var t0, t1 fp.Element + t0.Square(&x.A0) + t1.Square(&x.A1) + t0.Add(&t0, &t1) + t1.Inverse(&t0) + z.A0.Mul(&x.A0, &t1) + z.A1.Mul(&x.A1, &t1).Neg(&z.A1) + + return z +} + +// norm sets x to the norm of z +func (z *E2) norm(x *fp.Element) { + var tmp fp.Element + x.Square(&z.A0) + tmp.Square(&z.A1) + x.Add(x, &tmp) +} + +// MulBybTwistCurveCoeff multiplies by 4(1,1) +func (z *E2) MulBybTwistCurveCoeff(x *E2) *E2 { + + var res E2 + res.A0.Sub(&x.A0, &x.A1) + res.A1.Add(&x.A0, &x.A1) + z.Double(&res). + Double(z) + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381_fallback.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381_fallback.go new file mode 100644 index 00000000000..0ae39042dca --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_bls381_fallback.go @@ -0,0 +1,41 @@ +//go:build !amd64 +// +build !amd64 + +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + +// MulByNonResidue multiplies a E2 by (1,1) +func (z *E2) MulByNonResidue(x *E2) *E2 { + var a fp.Element + a.Sub(&x.A0, &x.A1) + z.A1.Add(&x.A0, &x.A1) + z.A0.Set(&a) + return z +} + +// Mul sets z to the E2-product of x,y, returns z +func (z *E2) Mul(x, y *E2) *E2 { + mulGenericE2(z, x, y) + return z +} + +// Square sets z to the E2-product of x,x returns z +func (z *E2) Square(x *E2) *E2 { + squareGenericE2(z, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_fallback.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_fallback.go new file mode 100644 index 00000000000..6fe47c4111b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e2_fallback.go @@ -0,0 +1,40 @@ +//go:build !amd64 +// +build !amd64 + +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +func addE2(z, x, y *E2) { + z.A0.Add(&x.A0, &y.A0) + z.A1.Add(&x.A1, &y.A1) +} + +func subE2(z, x, y *E2) { + z.A0.Sub(&x.A0, &y.A0) + z.A1.Sub(&x.A1, &y.A1) +} + +func doubleE2(z, x *E2) { + z.A0.Double(&x.A0) + z.A1.Double(&x.A1) +} + +func negE2(z, x *E2) { + z.A0.Neg(&x.A0) + z.A1.Neg(&x.A1) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e6.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e6.go new file mode 100644 index 00000000000..128007df278 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e6.go @@ -0,0 +1,339 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fptower + +// E6 is a degree three finite field extension of fp2 +type E6 struct { + B0, B1, B2 E2 +} + +// Equal returns true if z equals x, false otherwise +func (z *E6) Equal(x *E6) bool { + return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) && z.B2.Equal(&x.B2) +} + +// SetString sets a E6 elmt from stringf +func (z *E6) SetString(s1, s2, s3, s4, s5, s6 string) *E6 { + z.B0.SetString(s1, s2) + z.B1.SetString(s3, s4) + z.B2.SetString(s5, s6) + return z +} + +// Set Sets a E6 elmt form another E6 elmt +func (z *E6) Set(x *E6) *E6 { + z.B0 = x.B0 + z.B1 = x.B1 + z.B2 = x.B2 + return z +} + +// SetOne sets z to 1 in Montgomery form and returns z +func (z *E6) SetOne() *E6 { + *z = E6{} + z.B0.A0.SetOne() + return z +} + +// SetRandom set z to a random elmt +func (z *E6) SetRandom() (*E6, error) { + if _, err := z.B0.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B1.SetRandom(); err != nil { + return nil, err + } + if _, err := z.B2.SetRandom(); err != nil { + return nil, err + } + return z, nil +} + +// IsZero returns true if the two elements are equal, false otherwise +func (z *E6) IsZero() bool { + return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() +} + +func (z *E6) IsOne() bool { + return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() +} + +// Add adds two elements of E6 +func (z *E6) Add(x, y *E6) *E6 { + z.B0.Add(&x.B0, &y.B0) + z.B1.Add(&x.B1, &y.B1) + z.B2.Add(&x.B2, &y.B2) + return z +} + +// Neg negates the E6 number +func (z *E6) Neg(x *E6) *E6 { + z.B0.Neg(&x.B0) + z.B1.Neg(&x.B1) + z.B2.Neg(&x.B2) + return z +} + +// Sub two elements of E6 +func (z *E6) Sub(x, y *E6) *E6 { + z.B0.Sub(&x.B0, &y.B0) + z.B1.Sub(&x.B1, &y.B1) + z.B2.Sub(&x.B2, &y.B2) + return z +} + +// Double doubles an element in E6 +func (z *E6) Double(x *E6) *E6 { + z.B0.Double(&x.B0) + z.B1.Double(&x.B1) + z.B2.Double(&x.B2) + return z +} + +// String puts E6 elmt in string form +func (z *E6) String() string { + return (z.B0.String() + "+(" + z.B1.String() + ")*v+(" + z.B2.String() + ")*v**2") +} + +// MulByNonResidue mul x by (0,1,0) +func (z *E6) MulByNonResidue(x *E6) *E6 { + z.B2, z.B1, z.B0 = x.B1, x.B0, x.B2 + z.B0.MulByNonResidue(&z.B0) + return z +} + +// MulByE2 multiplies an element in E6 by an element in E2 +func (z *E6) MulByE2(x *E6, y *E2) *E6 { + var yCopy E2 + yCopy.Set(y) + z.B0.Mul(&x.B0, &yCopy) + z.B1.Mul(&x.B1, &yCopy) + z.B2.Mul(&x.B2, &yCopy) + return z +} + +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + +// MulBy01 multiplication by sparse element (c0,c1,0) +func (z *E6) MulBy01(c0, c1 *E2) *E6 { + + var a, b, tmp, t0, t1, t2 E2 + + a.Mul(&z.B0, c0) + b.Mul(&z.B1, c1) + + tmp.Add(&z.B1, &z.B2) + t0.Mul(c1, &tmp) + t0.Sub(&t0, &b) + t0.MulByNonResidue(&t0) + t0.Add(&t0, &a) + + tmp.Add(&z.B0, &z.B2) + t2.Mul(c0, &tmp) + t2.Sub(&t2, &a) + t2.Add(&t2, &b) + + t1.Add(c0, c1) + tmp.Add(&z.B0, &z.B1) + t1.Mul(&t1, &tmp) + t1.Sub(&t1, &a) + t1.Sub(&t1, &b) + + z.B0.Set(&t0) + z.B1.Set(&t1) + z.B2.Set(&t2) + + return z +} + +// MulBy1 multiplication of E6 by sparse element (0, c1, 0) +func (z *E6) MulBy1(c1 *E2) *E6 { + + var b, tmp, t0, t1 E2 + b.Mul(&z.B1, c1) + + tmp.Add(&z.B1, &z.B2) + t0.Mul(c1, &tmp) + t0.Sub(&t0, &b) + t0.MulByNonResidue(&t0) + + tmp.Add(&z.B0, &z.B1) + t1.Mul(c1, &tmp) + t1.Sub(&t1, &b) + + z.B0.Set(&t0) + z.B1.Set(&t1) + z.B2.Set(&b) + + return z +} + +// Mul sets z to the E6 product of x,y, returns z +func (z *E6) Mul(x, y *E6) *E6 { + // Algorithm 13 from https://eprint.iacr.org/2010/354.pdf + var t0, t1, t2, c0, c1, c2, tmp E2 + t0.Mul(&x.B0, &y.B0) + t1.Mul(&x.B1, &y.B1) + t2.Mul(&x.B2, &y.B2) + + c0.Add(&x.B1, &x.B2) + tmp.Add(&y.B1, &y.B2) + c0.Mul(&c0, &tmp).Sub(&c0, &t1).Sub(&c0, &t2).MulByNonResidue(&c0).Add(&c0, &t0) + + c1.Add(&x.B0, &x.B1) + tmp.Add(&y.B0, &y.B1) + c1.Mul(&c1, &tmp).Sub(&c1, &t0).Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + + tmp.Add(&x.B0, &x.B2) + c2.Add(&y.B0, &y.B2).Mul(&c2, &tmp).Sub(&c2, &t0).Sub(&c2, &t2).Add(&c2, &t1) + + z.B0.Set(&c0) + z.B1.Set(&c1) + z.B2.Set(&c2) + + return z +} + +// Square sets z to the E6 product of x,x, returns z +func (z *E6) Square(x *E6) *E6 { + + // Algorithm 16 from https://eprint.iacr.org/2010/354.pdf + var c4, c5, c1, c2, c3, c0 E2 + c4.Mul(&x.B0, &x.B1).Double(&c4) + c5.Square(&x.B2) + c1.MulByNonResidue(&c5).Add(&c1, &c4) + c2.Sub(&c4, &c5) + c3.Square(&x.B0) + c4.Sub(&x.B0, &x.B1).Add(&c4, &x.B2) + c5.Mul(&x.B1, &x.B2).Double(&c5) + c4.Square(&c4) + c0.MulByNonResidue(&c5).Add(&c0, &c3) + z.B2.Add(&c2, &c4).Add(&z.B2, &c5).Sub(&z.B2, &c3) + z.B0.Set(&c0) + z.B1.Set(&c1) + + return z +} + +// Inverse an element in E6 +// +// if x == 0, sets and returns z = x +func (z *E6) Inverse(x *E6) *E6 { + // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf + // step 9 is wrong in the paper it's t1-t4 + var t0, t1, t2, t3, t4, t5, t6, c0, c1, c2, d1, d2 E2 + t0.Square(&x.B0) + t1.Square(&x.B1) + t2.Square(&x.B2) + t3.Mul(&x.B0, &x.B1) + t4.Mul(&x.B0, &x.B2) + t5.Mul(&x.B1, &x.B2) + c0.MulByNonResidue(&t5).Neg(&c0).Add(&c0, &t0) + c1.MulByNonResidue(&t2).Sub(&c1, &t3) + c2.Sub(&t1, &t4) + t6.Mul(&x.B0, &c0) + d1.Mul(&x.B2, &c1) + d2.Mul(&x.B1, &c2) + d1.Add(&d1, &d2).MulByNonResidue(&d1) + t6.Add(&t6, &d1) + t6.Inverse(&t6) + z.B0.Mul(&c0, &t6) + z.B1.Mul(&c1, &t6) + z.B2.Mul(&c2, &t6) + + return z +} + +// BatchInvertE6 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE6(a []E6) []E6 { + res := make([]E6, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E6 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.B0.Select(cond, &caseZ.B0, &caseNz.B0) + z.B1.Select(cond, &caseZ.B1, &caseNz.B1) + z.B2.Select(cond, &caseZ.B2, &caseNz.B2) + + return z +} + +func (z *E6) Div(x *E6, y *E6) *E6 { + var r E6 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/frobenius.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/frobenius.go new file mode 100644 index 00000000000..94b38f42822 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/frobenius.go @@ -0,0 +1,261 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + +// Frobenius set z to Frobenius(x), return z +func (z *E12) Frobenius(x *E12) *E12 { + // Algorithm 28 from https://eprint.iacr.org/2010/354.pdf (beware typos!) + var t [6]E2 + + // Frobenius acts on fp2 by conjugation + t[0].Conjugate(&x.C0.B0) + t[1].Conjugate(&x.C0.B1) + t[2].Conjugate(&x.C0.B2) + t[3].Conjugate(&x.C1.B0) + t[4].Conjugate(&x.C1.B1) + t[5].Conjugate(&x.C1.B2) + + t[1].MulByNonResidue1Power2(&t[1]) + t[2].MulByNonResidue1Power4(&t[2]) + t[3].MulByNonResidue1Power1(&t[3]) + t[4].MulByNonResidue1Power3(&t[4]) + t[5].MulByNonResidue1Power5(&t[5]) + + z.C0.B0 = t[0] + z.C0.B1 = t[1] + z.C0.B2 = t[2] + z.C1.B0 = t[3] + z.C1.B1 = t[4] + z.C1.B2 = t[5] + + return z +} + +// FrobeniusSquare set z to Frobenius^2(x), and return z +func (z *E12) FrobeniusSquare(x *E12) *E12 { + // Algorithm 29 from https://eprint.iacr.org/2010/354.pdf (beware typos!) + + z.C0.B0 = x.C0.B0 + z.C0.B1.MulByNonResidue2Power2(&x.C0.B1) + z.C0.B2.MulByNonResidue2Power4(&x.C0.B2) + z.C1.B0.MulByNonResidue2Power1(&x.C1.B0) + z.C1.B1.MulByNonResidue2Power3(&x.C1.B1) + z.C1.B2.MulByNonResidue2Power5(&x.C1.B2) + + return z +} + +// MulByNonResidue1Power1 set z=x*(1,1)^(1*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power1(x *E2) *E2 { + // (3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760,151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027) + var b = E2{ + A0: fp.Element{ + 506819140503852133, + 14297063575771579155, + 10946065744702939791, + 11771194236670323182, + 2081670087578406477, + 644615147456521963, + }, + A1: fp.Element{ + 12895611875574011462, + 6359822009455181036, + 14936352902570693524, + 13914887797453940944, + 3330433690892295817, + 1229183470191017903, + }, + } + z.Mul(x, &b) + return z +} + +// MulByNonResidue1Power2 set z=x*(1,1)^(2*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power2(x *E2) *E2 { + // (0,4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436) + var b = E2{ + A0: fp.Element{ + 0, + 0, + 0, + 0, + 0, + 0, + }, + A1: fp.Element{ + 14772873186050699377, + 6749526151121446354, + 6372666795664677781, + 10283423008382700446, + 286397964926079186, + 1796971870900422465, + }, + } + z.Mul(x, &b) + return z +} + +// MulByNonResidue1Power3 set z=x*(1,1)^(3*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power3(x *E2) *E2 { + // (1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257,1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257) + var b = E2{ + A0: fp.Element{ + 8921533702591418330, + 15859389534032789116, + 3389114680249073393, + 15116930867080254631, + 3288288975085550621, + 1021049300055853010, + }, + A1: fp.Element{ + 8921533702591418330, + 15859389534032789116, + 3389114680249073393, + 15116930867080254631, + 3288288975085550621, + 1021049300055853010, + }, + } + z.Mul(x, &b) + return z +} + +// MulByNonResidue1Power4 set z=x*(1,1)^(4*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power4(x *E2) *E2 { + // 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437 + var b = fp.Element{ + 9875771541238924739, + 3094855109658912213, + 5802897354862067244, + 11677019699073781796, + 1505592401347711080, + 1505729768134575418, + } + z.A0.Mul(&x.A0, &b) + z.A1.Mul(&x.A1, &b) + return z +} + +// MulByNonResidue1Power5 set z=x*(1,1)^(5*(p^1-1)/6) and return z +func (z *E2) MulByNonResidue1Power5(x *E2) *E2 { + // (877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230,3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557) + var b = E2{ + A0: fp.Element{ + 9428352843095270463, + 11709709036094816655, + 14335180424952013185, + 8441381030041026197, + 5369959062663957099, + 1665664447512374973, + }, + A1: fp.Element{ + 3974078172982593132, + 8947176549131943536, + 11547238222321620130, + 17244701004083237929, + 42144715806745195, + 208134170135164893, + }, + } + z.Mul(x, &b) + return z +} + +// 793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351 +var nonResidue2Power1 = fp.Element{ + 17076301903736715834, + 13907359434105313836, + 1063007777899403918, + 15402659025741563681, + 5125705813544623108, + 76826746747117401, +} + +// MulByNonResidue2Power1 set z=x*(1,1)^(1*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power1(x *E2) *E2 { + z.A0.Mul(&x.A0, &nonResidue2Power1) + z.A1.Mul(&x.A1, &nonResidue2Power1) + return z +} + +// 793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350 +var nonResidue2Power2 = fp.Element{ + 3526659474838938856, + 17562030475567847978, + 1632777218702014455, + 14009062335050482331, + 3906511377122991214, + 368068849512964448, +} + +// MulByNonResidue2Power2 set z=x*(1,1)^(2*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power2(x *E2) *E2 { + z.A0.Mul(&x.A0, &nonResidue2Power2) + z.A1.Mul(&x.A1, &nonResidue2Power2) + return z +} + +// 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786 +var nonResidue2Power3 = fp.Element{ + 4897101644811774638, + 3654671041462534141, + 569769440802610537, + 17053147383018470266, + 17227549637287919721, + 291242102765847046, +} + +// MulByNonResidue2Power3 set z=x*(1,1)^(3*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power3(x *E2) *E2 { + z.A0.Mul(&x.A0, &nonResidue2Power3) + z.A1.Mul(&x.A1, &nonResidue2Power3) + return z +} + +// 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436 +var nonResidue2Power4 = fp.Element{ + 14772873186050699377, + 6749526151121446354, + 6372666795664677781, + 10283423008382700446, + 286397964926079186, + 1796971870900422465, +} + +// MulByNonResidue2Power4 set z=x*(1,1)^(4*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power4(x *E2) *E2 { + z.A0.Mul(&x.A0, &nonResidue2Power4) + z.A1.Mul(&x.A1, &nonResidue2Power4) + return z +} + +// 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437 +var nonResidue2Power5 = fp.Element{ + 9875771541238924739, + 3094855109658912213, + 5802897354862067244, + 11677019699073781796, + 1505592401347711080, + 1505729768134575418, +} + +// MulByNonResidue2Power5 set z=x*(1,1)^(5*(p^2-1)/6) and return z +func (z *E2) MulByNonResidue2Power5(x *E2) *E2 { + z.A0.Mul(&x.A0, &nonResidue2Power5) + z.A1.Mul(&x.A1, &nonResidue2Power5) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/parameters.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/parameters.go new file mode 100644 index 00000000000..9f97e117510 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/parameters.go @@ -0,0 +1,33 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +// generator of the curve +var xGen big.Int + +var glvBasis ecc.Lattice + +func init() { + xGen.SetString("-15132376222941642752", 10) + _r := fr.Modulus() + ecc.PrecomputeLattice(_r, &xGen, &glvBasis) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/marshal.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/marshal.go new file mode 100644 index 00000000000..8779479b249 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/marshal.go @@ -0,0 +1,1297 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +import ( + "encoding/binary" + "errors" + "io" + "reflect" + "sync/atomic" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" +) + +// To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity +// metadata needed for point (de)compression +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// see https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/11/ +// Appendix C. ZCash serialization format for BLS12_381 +const ( + mMask byte = 0b111 << 5 + mUncompressed byte = 0b000 << 5 + _ byte = 0b001 << 5 // invalid + mUncompressedInfinity byte = 0b010 << 5 + _ byte = 0b011 << 5 // invalid + mCompressedSmallest byte = 0b100 << 5 + mCompressedLargest byte = 0b101 << 5 + mCompressedInfinity byte = 0b110 << 5 + _ byte = 0b111 << 5 // invalid +) + +// SizeOfGT represents the size in bytes that a GT element need in binary form +const SizeOfGT = fptower.SizeOfGT + +var ( + ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + ErrInvalidEncoding = errors.New("invalid point encoding") +) + +// Encoder writes bls12-381 object values to an output stream +type Encoder struct { + w io.Writer + n int64 // written bytes + raw bool // raw vs compressed encoding +} + +// Decoder reads bls12-381 object values from an inbound stream +type Decoder struct { + r io.Reader + n int64 // read bytes + subGroupCheck bool // default to true +} + +// NewDecoder returns a binary decoder supporting curve bls12-381 objects in both +// compressed and uncompressed (raw) forms +func NewDecoder(r io.Reader, options ...func(*Decoder)) *Decoder { + d := &Decoder{r: r, subGroupCheck: true} + + for _, o := range options { + o(d) + } + + return d +} + +// Decode reads the binary encoding of v from the stream +// type must be *uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, *[]G1Affine or *[]G2Affine +func (dec *Decoder) Decode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { + return errors.New("bls12-381 decoder: unsupported type, need pointer") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + // in particular, careful attention must be given to usage of Bytes() method on Elements and Points + // that return an array (not a slice) of bytes. Using this is beneficial to minimize memory allocations + // in very large (de)serialization upstream in gnark. + // (but detrimental to code readability here) + + var read64 int64 + if vf, ok := v.(io.ReaderFrom); ok { + read64, err = vf.ReadFrom(dec.r) + dec.n += read64 + return + } + + var buf [SizeOfG2AffineUncompressed]byte + var read int + var sliceLen uint32 + + switch t := v.(type) { + case *[][]uint64: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + *t = make([][]uint64, sliceLen) + + for i := range *t { + if sliceLen, err = dec.readUint32(); err != nil { + return + } + (*t)[i] = make([]uint64, sliceLen) + for j := range (*t)[i] { + if (*t)[i][j], err = dec.readUint64(); err != nil { + return + } + } + } + return + case *[]uint64: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + *t = make([]uint64, sliceLen) + for i := range *t { + if (*t)[i], err = dec.readUint64(); err != nil { + return + } + } + return + case *fr.Element: + read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + err = t.SetBytesCanonical(buf[:fr.Bytes]) + return + case *fp.Element: + read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) + dec.n += int64(read) + if err != nil { + return + } + err = t.SetBytesCanonical(buf[:fp.Bytes]) + return + case *[]fr.Element: + read64, err = (*fr.Vector)(t).ReadFrom(dec.r) + dec.n += read64 + return + case *[]fp.Element: + read64, err = (*fp.Vector)(t).ReadFrom(dec.r) + dec.n += read64 + return + case *[][]fr.Element: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([][]fr.Element, sliceLen) + } + for i := range *t { + read64, err = (*fr.Vector)(&(*t)[i]).ReadFrom(dec.r) + dec.n += read64 + } + return + case *G1Affine: + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + } + _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) + return + case *G2Affine: + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG2AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG2AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG2AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG2AffineCompressed:SizeOfG2AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + } + _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) + return + case *[]G1Affine: + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) || *t == nil { + *t = make([]G1Affine, sliceLen) + } + compressed := make([]bool, sliceLen) + for i := 0; i < len(*t); i++ { + + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG1AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG1AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG1AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG1AffineCompressed:SizeOfG1AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + _, err = (*t)[i].setBytes(buf[:nbBytes], false) + if err != nil { + return + } + } else { + var r bool + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { + return + } + compressed[i] = !r + } + } + var nbErrs uint64 + parallel.Execute(len(compressed), func(start, end int) { + for i := start; i < end; i++ { + if compressed[i] { + if err := (*t)[i].unsafeComputeY(dec.subGroupCheck); err != nil { + atomic.AddUint64(&nbErrs, 1) + } + } else if dec.subGroupCheck { + if !(*t)[i].IsInSubGroup() { + atomic.AddUint64(&nbErrs, 1) + } + } + } + }) + if nbErrs != 0 { + return errors.New("point decompression failed") + } + + return nil + case *[]G2Affine: + sliceLen, err = dec.readUint32() + if err != nil { + return + } + if len(*t) != int(sliceLen) { + *t = make([]G2Affine, sliceLen) + } + compressed := make([]bool, sliceLen) + for i := 0; i < len(*t); i++ { + + // we start by reading compressed point size, if metadata tells us it is uncompressed, we read more. + read, err = io.ReadFull(dec.r, buf[:SizeOfG2AffineCompressed]) + dec.n += int64(read) + if err != nil { + return + } + nbBytes := SizeOfG2AffineCompressed + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(buf[0]) { + err = ErrInvalidEncoding + return + } + + // most significant byte contains metadata + if !isCompressed(buf[0]) { + nbBytes = SizeOfG2AffineUncompressed + // we read more. + read, err = io.ReadFull(dec.r, buf[SizeOfG2AffineCompressed:SizeOfG2AffineUncompressed]) + dec.n += int64(read) + if err != nil { + return + } + _, err = (*t)[i].setBytes(buf[:nbBytes], false) + if err != nil { + return + } + } else { + var r bool + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { + return + } + compressed[i] = !r + } + } + var nbErrs uint64 + parallel.Execute(len(compressed), func(start, end int) { + for i := start; i < end; i++ { + if compressed[i] { + if err := (*t)[i].unsafeComputeY(dec.subGroupCheck); err != nil { + atomic.AddUint64(&nbErrs, 1) + } + } else if dec.subGroupCheck { + if !(*t)[i].IsInSubGroup() { + atomic.AddUint64(&nbErrs, 1) + } + } + } + }) + if nbErrs != 0 { + return errors.New("point decompression failed") + } + + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New("bls12-381 encoder: unsupported type") + } + err = binary.Read(dec.r, binary.BigEndian, t) + if err == nil { + dec.n += int64(n) + } + return + } +} + +// BytesRead return total bytes read from reader +func (dec *Decoder) BytesRead() int64 { + return dec.n +} + +func (dec *Decoder) readUint32() (r uint32, err error) { + var read int + var buf [4]byte + read, err = io.ReadFull(dec.r, buf[:4]) + dec.n += int64(read) + if err != nil { + return + } + r = binary.BigEndian.Uint32(buf[:4]) + return +} + +func (dec *Decoder) readUint64() (r uint64, err error) { + var read int + var buf [8]byte + read, err = io.ReadFull(dec.r, buf[:]) + dec.n += int64(read) + if err != nil { + return + } + r = binary.BigEndian.Uint64(buf[:]) + return +} + +// isMaskInvalid returns true if the mask is invalid +func isMaskInvalid(msb byte) bool { + mData := msb & mMask + return ((mData == (0b111 << 5)) || (mData == (0b011 << 5)) || (mData == (0b001 << 5))) +} + +func isCompressed(msb byte) bool { + mData := msb & mMask + return !((mData == mUncompressed) || (mData == mUncompressedInfinity)) +} + +// NewEncoder returns a binary encoder supporting curve bls12-381 objects +func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { + // default settings + enc := &Encoder{ + w: w, + n: 0, + raw: false, + } + + // handle options + for _, option := range options { + option(enc) + } + + return enc +} + +// Encode writes the binary encoding of v to the stream +// type must be uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, []G1Affine or []G2Affine +func (enc *Encoder) Encode(v interface{}) (err error) { + if enc.raw { + return enc.encodeRaw(v) + } + return enc.encode(v) +} + +// BytesWritten return total bytes written on writer +func (enc *Encoder) BytesWritten() int64 { + return enc.n +} + +// RawEncoding returns an option to use in NewEncoder(...) which sets raw encoding mode to true +// points will not be compressed using this option +func RawEncoding() func(*Encoder) { + return func(enc *Encoder) { + enc.raw = true + } +} + +// NoSubgroupChecks returns an option to use in NewDecoder(...) which disable subgroup checks on the points +// the decoder will read. Use with caution, as crafted points from an untrusted source can lead to crypto-attacks. +func NoSubgroupChecks() func(*Decoder) { + return func(dec *Decoder) { + dec.subGroupCheck = false + } +} + +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + +func (enc *Encoder) encode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + + var written64 int64 + if vw, ok := v.(io.WriterTo); ok { + written64, err = vw.WriteTo(enc.w) + enc.n += written64 + return + } + + var written int + + switch t := v.(type) { + case []uint64: + return enc.writeUint64Slice(t) + case [][]uint64: + return enc.writeUint64SliceSlice(t) + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G2Affine: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case fr.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case fp.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case []fr.Element: + written64, err = (*fr.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case []fp.Element: + written64, err = (*fp.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case [][]fr.Element: + // write slice length + if err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))); err != nil { + return + } + enc.n += 4 + for i := range t { + written64, err = (*fr.Vector)(&t[i]).WriteTo(enc.w) + enc.n += written64 + } + return + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineCompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []G2Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG2AffineCompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} + +func (enc *Encoder) encodeRaw(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } + + // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap + + var written64 int64 + if vw, ok := v.(io.WriterTo); ok { + written64, err = vw.WriteTo(enc.w) + enc.n += written64 + return + } + + var written int + + switch t := v.(type) { + case []uint64: + return enc.writeUint64Slice(t) + case [][]uint64: + return enc.writeUint64SliceSlice(t) + case *fr.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *fp.Element: + buf := t.Bytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G1Affine: + buf := t.RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case *G2Affine: + buf := t.RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + return + case fr.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case fp.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case []fr.Element: + written64, err = (*fr.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case []fp.Element: + written64, err = (*fp.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case [][]fr.Element: + // write slice length + if err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))); err != nil { + return + } + enc.n += 4 + for i := range t { + written64, err = (*fr.Vector)(&t[i]).WriteTo(enc.w) + enc.n += written64 + } + return + case []G1Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG1AffineUncompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + case []G2Affine: + // write slice length + err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) + if err != nil { + return + } + enc.n += 4 + + var buf [SizeOfG2AffineUncompressed]byte + + for i := 0; i < len(t); i++ { + buf = t[i].RawBytes() + written, err = enc.w.Write(buf[:]) + enc.n += int64(written) + if err != nil { + return + } + } + return nil + default: + n := binary.Size(t) + if n == -1 { + return errors.New(" encoder: unsupported type") + } + err = binary.Write(enc.w, binary.BigEndian, t) + enc.n += int64(n) + return + } +} + +func (enc *Encoder) writeUint64Slice(t []uint64) (err error) { + if err = enc.writeUint32(uint32(len(t))); err != nil { + return + } + for i := range t { + if err = enc.writeUint64(t[i]); err != nil { + return + } + } + return nil +} + +func (enc *Encoder) writeUint64SliceSlice(t [][]uint64) (err error) { + if err = enc.writeUint32(uint32(len(t))); err != nil { + return + } + for i := range t { + if err = enc.writeUint32(uint32(len(t[i]))); err != nil { + return + } + for j := range t[i] { + if err = enc.writeUint64(t[i][j]); err != nil { + return + } + } + } + return nil +} + +func (enc *Encoder) writeUint64(a uint64) error { + var buff [64 / 8]byte + binary.BigEndian.PutUint64(buff[:], a) + written, err := enc.w.Write(buff[:]) + enc.n += int64(written) + return err +} + +func (enc *Encoder) writeUint32(a uint32) error { + var buff [32 / 8]byte + binary.BigEndian.PutUint32(buff[:], a) + written, err := enc.w.Write(buff[:]) + enc.n += int64(written) + return err +} + +// SizeOfG1AffineCompressed represents the size in bytes that a G1Affine need in binary form, compressed +const SizeOfG1AffineCompressed = 48 + +// SizeOfG1AffineUncompressed represents the size in bytes that a G1Affine need in binary form, uncompressed +const SizeOfG1AffineUncompressed = SizeOfG1AffineCompressed * 2 + +// Marshal converts p to a byte slice (without point compression) +func (p *G1Affine) Marshal() []byte { + b := p.RawBytes() + return b[:] +} + +// Unmarshal is an alias to SetBytes() +func (p *G1Affine) Unmarshal(buf []byte) error { + _, err := p.SetBytes(buf) + return err +} + +// Bytes returns binary representation of p +// will store X coordinate in regular form and a parity bit +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// +// The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. +// +// The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. +// +// The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. +func (p *G1Affine) Bytes() (res [SizeOfG1AffineCompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + res[0] = mCompressedInfinity + return + } + + msbMask := mCompressedSmallest + // compressed, we need to know if Y is lexicographically bigger than -Y + // if p.Y ">" -p.Y + if p.Y.LexicographicallyLargest() { + msbMask = mCompressedLargest + } + + // we store X and mask the most significant word with our metadata mask + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + + res[0] |= msbMask + + return +} + +// RawBytes returns binary representation of p (stores X and Y coordinate) +// see Bytes() for a compressed representation +func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + + res[0] = mUncompressedInfinity + + return + } + + // not compressed + // we store the Y coordinate + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.Y) + + // we store X and mask the most significant word with our metadata mask + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) + + res[0] |= mUncompressed + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// +// bytes in buf must match either RawBytes() or Bytes() output +// +// if buf is too short io.ErrShortBuffer is returned +// +// if buf contains compressed representation (output from Bytes()) and we're unable to compute +// the Y coordinate (i.e the square root doesn't exist) this function returns an error +// +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G1Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG1AffineCompressed { + return 0, io.ErrShortBuffer + } + + // most significant byte + mData := buf[0] & mMask + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(mData) { + return 0, ErrInvalidEncoding + } + + // check buffer size + if (mData == mUncompressed) || (mData == mUncompressedInfinity) { + if len(buf) < SizeOfG1AffineUncompressed { + return 0, io.ErrShortBuffer + } + } + + // infinity encoded, we still check that the buffer is full of zeroes. + if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG1AffineCompressed, nil + } + if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG1AffineUncompressed, nil + } + + // uncompressed point + if mData == mUncompressed { + // read X and Y coordinates + if err := p.X.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.Y.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineUncompressed, nil + } + + // we have a compressed coordinate + // we need to + // 1. copy the buffer (to keep this method thread safe) + // 2. we need to solve the curve equation to compute Y + + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return 0, err + } + + var YSquared, Y fp.Element + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { + return 0, errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG1AffineCompressed, nil +} + +// unsafeComputeY called by Decoder when processing slices of compressed point in parallel (step 2) +// it computes the Y coordinate from the already set X coordinate and is compute intensive +func (p *G1Affine) unsafeComputeY(subGroupCheck bool) error { + // stored in unsafeSetCompressedBytes + + mData := byte(p.Y[0]) + + // we have a compressed coordinate, we need to solve the curve equation to compute Y + var YSquared, Y fp.Element + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bCurveCoeff) + if Y.Sqrt(&YSquared) == nil { + return errors.New("invalid compressed coordinate: square root doesn't exist") + } + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return errors.New("invalid point: subgroup check failed") + } + + return nil +} + +// unsafeSetCompressedBytes is called by Decoder when processing slices of compressed point in parallel (step 1) +// assumes buf[:8] mask is set to compressed +// returns true if point is infinity and need no further processing +// it sets X coordinate and uses Y for scratch space to store decompression metadata +func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err error) { + + // read the most significant byte + mData := buf[0] & mMask + + if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return isInfinity, nil + } + + // we need to copy the input buffer (to keep this method thread safe) + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return false, err + } + // store mData in p.Y[0] + p.Y[0] = uint64(mData) + + // recomputing Y will be done asynchronously + return isInfinity, nil +} + +// SizeOfG2AffineCompressed represents the size in bytes that a G2Affine need in binary form, compressed +const SizeOfG2AffineCompressed = 48 * 2 + +// SizeOfG2AffineUncompressed represents the size in bytes that a G2Affine need in binary form, uncompressed +const SizeOfG2AffineUncompressed = SizeOfG2AffineCompressed * 2 + +// Marshal converts p to a byte slice (without point compression) +func (p *G2Affine) Marshal() []byte { + b := p.RawBytes() + return b[:] +} + +// Unmarshal is an alias to SetBytes() +func (p *G2Affine) Unmarshal(buf []byte) error { + _, err := p.SetBytes(buf) + return err +} + +// Bytes returns binary representation of p +// will store X coordinate in regular form and a parity bit +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF +// +// The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. +// +// The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. +// +// The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. +func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + res[0] = mCompressedInfinity + return + } + + msbMask := mCompressedSmallest + // compressed, we need to know if Y is lexicographically bigger than -Y + // if p.Y ">" -p.Y + if p.Y.LexicographicallyLargest() { + msbMask = mCompressedLargest + } + + // we store X and mask the most significant word with our metadata mask + // p.X.A1 | p.X.A0 + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.X.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) + + res[0] |= msbMask + + return +} + +// RawBytes returns binary representation of p (stores X and Y coordinate) +// see Bytes() for a compressed representation +func (p *G2Affine) RawBytes() (res [SizeOfG2AffineUncompressed]byte) { + + // check if p is infinity point + if p.X.IsZero() && p.Y.IsZero() { + + res[0] = mUncompressedInfinity + + return + } + + // not compressed + // we store the Y coordinate + // p.Y.A1 | p.Y.A0 + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[144:144+fp.Bytes]), p.Y.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[96:96+fp.Bytes]), p.Y.A1) + + // we store X and mask the most significant word with our metadata mask + // p.X.A1 | p.X.A0 + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.X.A0) + + res[0] |= mUncompressed + + return +} + +// SetBytes sets p from binary representation in buf and returns number of consumed bytes +// +// bytes in buf must match either RawBytes() or Bytes() output +// +// if buf is too short io.ErrShortBuffer is returned +// +// if buf contains compressed representation (output from Bytes()) and we're unable to compute +// the Y coordinate (i.e the square root doesn't exist) this function returns an error +// +// this check if the resulting point is on the curve and in the correct subgroup +func (p *G2Affine) SetBytes(buf []byte) (int, error) { + return p.setBytes(buf, true) +} + +func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { + if len(buf) < SizeOfG2AffineCompressed { + return 0, io.ErrShortBuffer + } + + // most significant byte + mData := buf[0] & mMask + + // 111, 011, 001 --> invalid mask + if isMaskInvalid(mData) { + return 0, ErrInvalidEncoding + } + + // check buffer size + if (mData == mUncompressed) || (mData == mUncompressedInfinity) { + if len(buf) < SizeOfG2AffineUncompressed { + return 0, io.ErrShortBuffer + } + } + + // infinity encoded, we still check that the buffer is full of zeroes. + if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG2AffineCompressed, nil + } + if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return SizeOfG2AffineUncompressed, nil + } + + // uncompressed point + if mData == mUncompressed { + // read X and Y coordinates + // p.X.A1 | p.X.A0 + if err := p.X.A1.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + // p.Y.A1 | p.Y.A0 + if err := p.Y.A1.SetBytesCanonical(buf[fp.Bytes*2 : fp.Bytes*3]); err != nil { + return 0, err + } + if err := p.Y.A0.SetBytesCanonical(buf[fp.Bytes*3 : fp.Bytes*4]); err != nil { + return 0, err + } + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG2AffineUncompressed, nil + } + + // we have a compressed coordinate + // we need to + // 1. copy the buffer (to keep this method thread safe) + // 2. we need to solve the curve equation to compute Y + + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + // p.X.A1 | p.X.A0 + if err := p.X.A1.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } + + var YSquared, Y fptower.E2 + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bTwistCurveCoeff) + if YSquared.Legendre() == -1 { + return 0, errors.New("invalid compressed coordinate: square root doesn't exist") + } + Y.Sqrt(&YSquared) + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return 0, errors.New("invalid point: subgroup check failed") + } + + return SizeOfG2AffineCompressed, nil +} + +// unsafeComputeY called by Decoder when processing slices of compressed point in parallel (step 2) +// it computes the Y coordinate from the already set X coordinate and is compute intensive +func (p *G2Affine) unsafeComputeY(subGroupCheck bool) error { + // stored in unsafeSetCompressedBytes + + mData := byte(p.Y.A0[0]) + + // we have a compressed coordinate, we need to solve the curve equation to compute Y + var YSquared, Y fptower.E2 + + YSquared.Square(&p.X).Mul(&YSquared, &p.X) + YSquared.Add(&YSquared, &bTwistCurveCoeff) + if YSquared.Legendre() == -1 { + return errors.New("invalid compressed coordinate: square root doesn't exist") + } + Y.Sqrt(&YSquared) + + if Y.LexicographicallyLargest() { + // Y ">" -Y + if mData == mCompressedSmallest { + Y.Neg(&Y) + } + } else { + // Y "<=" -Y + if mData == mCompressedLargest { + Y.Neg(&Y) + } + } + + p.Y = Y + + // subgroup check + if subGroupCheck && !p.IsInSubGroup() { + return errors.New("invalid point: subgroup check failed") + } + + return nil +} + +// unsafeSetCompressedBytes is called by Decoder when processing slices of compressed point in parallel (step 1) +// assumes buf[:8] mask is set to compressed +// returns true if point is infinity and need no further processing +// it sets X coordinate and uses Y for scratch space to store decompression metadata +func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err error) { + + // read the most significant byte + mData := buf[0] & mMask + + if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } + p.X.SetZero() + p.Y.SetZero() + return isInfinity, nil + } + + // we need to copy the input buffer (to keep this method thread safe) + var bufX [fp.Bytes]byte + copy(bufX[:fp.Bytes], buf[:fp.Bytes]) + bufX[0] &= ^mMask + + // read X coordinate + // p.X.A1 | p.X.A0 + if err := p.X.A1.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return false, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return false, err + } + + // store mData in p.Y.A0[0] + p.Y.A0[0] = uint64(mData) + + // recomputing Y will be done asynchronously + return isInfinity, nil +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp.go new file mode 100644 index 00000000000..19350818ff0 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp.go @@ -0,0 +1,813 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +import ( + "errors" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/internal/parallel" + "math" + "runtime" +) + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Affine, error) { + var _p G1Jac + if _, err := _p.MultiExp(points, scalars, config); err != nil { + return nil, err + } + p.FromJacobian(&_p) + return p, nil +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Jac, error) { + // TODO @gbotrel replace the ecc.MultiExpConfig by a Option pattern for maintainability. + // note: + // each of the msmCX method is the same, except for the c constant it declares + // duplicating (through template generation) these methods allows to declare the buckets on the stack + // the choice of c needs to be improved: + // there is a theoretical value that gives optimal asymptotics + // but in practice, other factors come into play, including: + // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 + // * number of CPUs + // * cache friendliness (which depends on the host, G1 or G2... ) + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + + // for each msmCX + // step 1 + // we compute, for each scalars over c-bit wide windows, nbChunk digits + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + // negative digits will be processed in the next step as adding -G into the bucket instead of G + // (computing -G is cheap, and this saves us half of the buckets) + // step 2 + // buckets are declared on the stack + // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) + // we use jacobian extended formulas here as they are faster than mixed addition + // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel + // step 3 + // reduce the buckets weighed sums into our result (msmReduceChunk) + + // ensure len(points) == len(scalars) + nbPoints := len(points) + if nbPoints != len(scalars) { + return nil, errors.New("len(points) != len(scalars)") + } + + // if nbTasks is not set, use all available CPUs + if config.NbTasks <= 0 { + config.NbTasks = runtime.NumCPU() * 2 + } else if config.NbTasks > 1024 { + return nil, errors.New("invalid config: config.NbTasks > 1024") + } + + // here, we compute the best C for nbPoints + // we split recursively until nbChunks(c) >= nbTasks, + bestC := func(nbPoints int) uint64 { + // implemented msmC methods (the c we use must be in this slice) + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + var C uint64 + // approximate cost (in group operations) + // cost = bits/c * (nbPoints + 2^{c}) + // this needs to be verified empirically. + // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results + min := math.MaxFloat64 + for _, c := range implementedCs { + cc := (fr.Bits + 1) * (nbPoints + (1 << c)) + cost := float64(cc) / float64(c) + if cost < min { + min = cost + C = c + } + } + return C + } + + C := bestC(nbPoints) + nbChunks := int(computeNbChunks(C)) + + // should we recursively split the msm in half? (see below) + // we want to minimize the execution time of the algorithm; + // splitting the msm will **add** operations, but if it allows to use more CPU, it might be worth it. + + // costFunction returns a metric that represent the "wall time" of the algorithm + costFunction := func(nbTasks, nbCpus, costPerTask int) int { + // cost for the reduction of all tasks (msmReduceChunk) + totalCost := nbTasks + + // cost for the computation of each task (msmProcessChunk) + for nbTasks >= nbCpus { + nbTasks -= nbCpus + totalCost += costPerTask + } + if nbTasks > 0 { + totalCost += costPerTask + } + return totalCost + } + + // costPerTask is the approximate number of group ops per task + costPerTask := func(c uint64, nbPoints int) int { return (nbPoints + int((1 << c))) } + + costPreSplit := costFunction(nbChunks, config.NbTasks, costPerTask(C, nbPoints)) + + cPostSplit := bestC(nbPoints / 2) + nbChunksPostSplit := int(computeNbChunks(cPostSplit)) + costPostSplit := costFunction(nbChunksPostSplit*2, config.NbTasks, costPerTask(cPostSplit, nbPoints/2)) + + // if the cost of the split msm is lower than the cost of the non split msm, we split + if costPostSplit < costPreSplit { + config.NbTasks = int(math.Ceil(float64(config.NbTasks) / 2.0)) + var _p G1Jac + chDone := make(chan struct{}, 1) + go func() { + _p.MultiExp(points[:nbPoints/2], scalars[:nbPoints/2], config) + close(chDone) + }() + p.MultiExp(points[nbPoints/2:], scalars[nbPoints/2:], config) + <-chDone + p.AddAssign(&_p) + return p, nil + } + + // if we don't split, we use the best C we found + _innerMsmG1(p, C, points, scalars, config) + + return p, nil +} + +func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) *G1Jac { + // partition the scalars + digits, chunkStats := partitionScalars(scalars, c, config.NbTasks) + + nbChunks := computeNbChunks(c) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack and this is critical for performance + + // each go routine sends its result in chChunks[i] channel + chChunks := make([]chan g1JacExtended, nbChunks) + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // we use a semaphore to limit the number of go routines running concurrently + // (only if nbTasks < nbCPU) + var sem chan struct{} + if config.NbTasks < runtime.NumCPU() { + // we add nbChunks because if chunk is overweight we split it in two + sem = make(chan struct{}, config.NbTasks+int(nbChunks)) + for i := 0; i < config.NbTasks; i++ { + sem <- struct{}{} + } + defer func() { + close(sem) + }() + } + + // the last chunk may be processed with a different method than the rest, as it could be smaller. + n := len(points) + for j := int(nbChunks - 1); j >= 0; j-- { + processChunk := getChunkProcessorG1(c, chunkStats[j]) + if j == int(nbChunks-1) { + processChunk = getChunkProcessorG1(lastC(c), chunkStats[j]) + } + if chunkStats[j].weight >= 115 { + // we split this in more go routines since this chunk has more work to do than the others. + // else what would happen is this go routine would finish much later than the others. + chSplit := make(chan g1JacExtended, 2) + split := n / 2 + + if sem != nil { + sem <- struct{}{} // add another token to the semaphore, since we split in two. + } + go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split], sem) + go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n], sem) + go func(chunkID int) { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[chunkID] <- s1 + }(j) + continue + } + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) + } + + return msmReduceChunkG1Affine(p, int(c), chChunks[:]) +} + +// getChunkProcessorG1 decides, depending on c window size and statistics for the chunk +// to return the best algorithm to process the chunk. +func getChunkProcessorG1(c uint64, stat chunkStat) func(chunkID uint64, chRes chan<- g1JacExtended, c uint64, points []G1Affine, digits []uint16, sem chan struct{}) { + switch c { + + case 3: + return processChunkG1Jacobian[bucketg1JacExtendedC3] + case 4: + return processChunkG1Jacobian[bucketg1JacExtendedC4] + case 5: + return processChunkG1Jacobian[bucketg1JacExtendedC5] + case 6: + return processChunkG1Jacobian[bucketg1JacExtendedC6] + case 7: + return processChunkG1Jacobian[bucketg1JacExtendedC7] + case 8: + return processChunkG1Jacobian[bucketg1JacExtendedC8] + case 9: + return processChunkG1Jacobian[bucketg1JacExtendedC9] + case 10: + const batchSize = 80 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC10] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC10, bucketG1AffineC10, bitSetC10, pG1AffineC10, ppG1AffineC10, qG1AffineC10, cG1AffineC10] + case 11: + const batchSize = 150 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC11] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC11, bucketG1AffineC11, bitSetC11, pG1AffineC11, ppG1AffineC11, qG1AffineC11, cG1AffineC11] + case 12: + const batchSize = 200 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC12] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC12, bucketG1AffineC12, bitSetC12, pG1AffineC12, ppG1AffineC12, qG1AffineC12, cG1AffineC12] + case 13: + const batchSize = 350 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC13] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC13, bucketG1AffineC13, bitSetC13, pG1AffineC13, ppG1AffineC13, qG1AffineC13, cG1AffineC13] + case 14: + const batchSize = 400 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC14] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC14, bucketG1AffineC14, bitSetC14, pG1AffineC14, ppG1AffineC14, qG1AffineC14, cG1AffineC14] + case 15: + const batchSize = 500 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC15] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC15, bucketG1AffineC15, bitSetC15, pG1AffineC15, ppG1AffineC15, qG1AffineC15, cG1AffineC15] + case 16: + const batchSize = 640 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC16] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC16, bucketG1AffineC16, bitSetC16, pG1AffineC16, ppG1AffineC16, qG1AffineC16, cG1AffineC16] + default: + // panic("will not happen c != previous values is not generated by templates") + return processChunkG1Jacobian[bucketg1JacExtendedC16] + } +} + +// msmReduceChunkG1Affine reduces the weighted sum of the buckets into the result of the multiExp +func msmReduceChunkG1Affine(p *G1Jac, c int, chChunks []chan g1JacExtended) *G1Jac { + var _p g1JacExtended + totalj := <-chChunks[len(chChunks)-1] + _p.Set(&totalj) + for j := len(chChunks) - 2; j >= 0; j-- { + for l := 0; l < c; l++ { + _p.double(&_p) + } + totalj := <-chChunks[j] + _p.add(&totalj) + } + + return p.unsafeFromJacExtended(&_p) +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Affine, error) { + var _p G2Jac + if _, err := _p.MultiExp(points, scalars, config); err != nil { + return nil, err + } + p.FromJacobian(&_p) + return p, nil +} + +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Jac, error) { + // TODO @gbotrel replace the ecc.MultiExpConfig by a Option pattern for maintainability. + // note: + // each of the msmCX method is the same, except for the c constant it declares + // duplicating (through template generation) these methods allows to declare the buckets on the stack + // the choice of c needs to be improved: + // there is a theoretical value that gives optimal asymptotics + // but in practice, other factors come into play, including: + // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 + // * number of CPUs + // * cache friendliness (which depends on the host, G1 or G2... ) + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + + // for each msmCX + // step 1 + // we compute, for each scalars over c-bit wide windows, nbChunk digits + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + // negative digits will be processed in the next step as adding -G into the bucket instead of G + // (computing -G is cheap, and this saves us half of the buckets) + // step 2 + // buckets are declared on the stack + // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) + // we use jacobian extended formulas here as they are faster than mixed addition + // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel + // step 3 + // reduce the buckets weighed sums into our result (msmReduceChunk) + + // ensure len(points) == len(scalars) + nbPoints := len(points) + if nbPoints != len(scalars) { + return nil, errors.New("len(points) != len(scalars)") + } + + // if nbTasks is not set, use all available CPUs + if config.NbTasks <= 0 { + config.NbTasks = runtime.NumCPU() * 2 + } else if config.NbTasks > 1024 { + return nil, errors.New("invalid config: config.NbTasks > 1024") + } + + // here, we compute the best C for nbPoints + // we split recursively until nbChunks(c) >= nbTasks, + bestC := func(nbPoints int) uint64 { + // implemented msmC methods (the c we use must be in this slice) + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + var C uint64 + // approximate cost (in group operations) + // cost = bits/c * (nbPoints + 2^{c}) + // this needs to be verified empirically. + // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results + min := math.MaxFloat64 + for _, c := range implementedCs { + cc := (fr.Bits + 1) * (nbPoints + (1 << c)) + cost := float64(cc) / float64(c) + if cost < min { + min = cost + C = c + } + } + return C + } + + C := bestC(nbPoints) + nbChunks := int(computeNbChunks(C)) + + // should we recursively split the msm in half? (see below) + // we want to minimize the execution time of the algorithm; + // splitting the msm will **add** operations, but if it allows to use more CPU, it might be worth it. + + // costFunction returns a metric that represent the "wall time" of the algorithm + costFunction := func(nbTasks, nbCpus, costPerTask int) int { + // cost for the reduction of all tasks (msmReduceChunk) + totalCost := nbTasks + + // cost for the computation of each task (msmProcessChunk) + for nbTasks >= nbCpus { + nbTasks -= nbCpus + totalCost += costPerTask + } + if nbTasks > 0 { + totalCost += costPerTask + } + return totalCost + } + + // costPerTask is the approximate number of group ops per task + costPerTask := func(c uint64, nbPoints int) int { return (nbPoints + int((1 << c))) } + + costPreSplit := costFunction(nbChunks, config.NbTasks, costPerTask(C, nbPoints)) + + cPostSplit := bestC(nbPoints / 2) + nbChunksPostSplit := int(computeNbChunks(cPostSplit)) + costPostSplit := costFunction(nbChunksPostSplit*2, config.NbTasks, costPerTask(cPostSplit, nbPoints/2)) + + // if the cost of the split msm is lower than the cost of the non split msm, we split + if costPostSplit < costPreSplit { + config.NbTasks = int(math.Ceil(float64(config.NbTasks) / 2.0)) + var _p G2Jac + chDone := make(chan struct{}, 1) + go func() { + _p.MultiExp(points[:nbPoints/2], scalars[:nbPoints/2], config) + close(chDone) + }() + p.MultiExp(points[nbPoints/2:], scalars[nbPoints/2:], config) + <-chDone + p.AddAssign(&_p) + return p, nil + } + + // if we don't split, we use the best C we found + _innerMsmG2(p, C, points, scalars, config) + + return p, nil +} + +func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) *G2Jac { + // partition the scalars + digits, chunkStats := partitionScalars(scalars, c, config.NbTasks) + + nbChunks := computeNbChunks(c) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack and this is critical for performance + + // each go routine sends its result in chChunks[i] channel + chChunks := make([]chan g2JacExtended, nbChunks) + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g2JacExtended, 1) + } + + // we use a semaphore to limit the number of go routines running concurrently + // (only if nbTasks < nbCPU) + var sem chan struct{} + if config.NbTasks < runtime.NumCPU() { + // we add nbChunks because if chunk is overweight we split it in two + sem = make(chan struct{}, config.NbTasks+int(nbChunks)) + for i := 0; i < config.NbTasks; i++ { + sem <- struct{}{} + } + defer func() { + close(sem) + }() + } + + // the last chunk may be processed with a different method than the rest, as it could be smaller. + n := len(points) + for j := int(nbChunks - 1); j >= 0; j-- { + processChunk := getChunkProcessorG2(c, chunkStats[j]) + if j == int(nbChunks-1) { + processChunk = getChunkProcessorG2(lastC(c), chunkStats[j]) + } + if chunkStats[j].weight >= 115 { + // we split this in more go routines since this chunk has more work to do than the others. + // else what would happen is this go routine would finish much later than the others. + chSplit := make(chan g2JacExtended, 2) + split := n / 2 + + if sem != nil { + sem <- struct{}{} // add another token to the semaphore, since we split in two. + } + go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split], sem) + go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n], sem) + go func(chunkID int) { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[chunkID] <- s1 + }(j) + continue + } + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) + } + + return msmReduceChunkG2Affine(p, int(c), chChunks[:]) +} + +// getChunkProcessorG2 decides, depending on c window size and statistics for the chunk +// to return the best algorithm to process the chunk. +func getChunkProcessorG2(c uint64, stat chunkStat) func(chunkID uint64, chRes chan<- g2JacExtended, c uint64, points []G2Affine, digits []uint16, sem chan struct{}) { + switch c { + + case 3: + return processChunkG2Jacobian[bucketg2JacExtendedC3] + case 4: + return processChunkG2Jacobian[bucketg2JacExtendedC4] + case 5: + return processChunkG2Jacobian[bucketg2JacExtendedC5] + case 6: + return processChunkG2Jacobian[bucketg2JacExtendedC6] + case 7: + return processChunkG2Jacobian[bucketg2JacExtendedC7] + case 8: + return processChunkG2Jacobian[bucketg2JacExtendedC8] + case 9: + return processChunkG2Jacobian[bucketg2JacExtendedC9] + case 10: + const batchSize = 80 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC10] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC10, bucketG2AffineC10, bitSetC10, pG2AffineC10, ppG2AffineC10, qG2AffineC10, cG2AffineC10] + case 11: + const batchSize = 150 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC11] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC11, bucketG2AffineC11, bitSetC11, pG2AffineC11, ppG2AffineC11, qG2AffineC11, cG2AffineC11] + case 12: + const batchSize = 200 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC12] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC12, bucketG2AffineC12, bitSetC12, pG2AffineC12, ppG2AffineC12, qG2AffineC12, cG2AffineC12] + case 13: + const batchSize = 350 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC13] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC13, bucketG2AffineC13, bitSetC13, pG2AffineC13, ppG2AffineC13, qG2AffineC13, cG2AffineC13] + case 14: + const batchSize = 400 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC14] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC14, bucketG2AffineC14, bitSetC14, pG2AffineC14, ppG2AffineC14, qG2AffineC14, cG2AffineC14] + case 15: + const batchSize = 500 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC15] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC15, bucketG2AffineC15, bitSetC15, pG2AffineC15, ppG2AffineC15, qG2AffineC15, cG2AffineC15] + case 16: + const batchSize = 640 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC16] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC16, bucketG2AffineC16, bitSetC16, pG2AffineC16, ppG2AffineC16, qG2AffineC16, cG2AffineC16] + default: + // panic("will not happen c != previous values is not generated by templates") + return processChunkG2Jacobian[bucketg2JacExtendedC16] + } +} + +// msmReduceChunkG2Affine reduces the weighted sum of the buckets into the result of the multiExp +func msmReduceChunkG2Affine(p *G2Jac, c int, chChunks []chan g2JacExtended) *G2Jac { + var _p g2JacExtended + totalj := <-chChunks[len(chChunks)-1] + _p.Set(&totalj) + for j := len(chChunks) - 2; j >= 0; j-- { + for l := 0; l < c; l++ { + _p.double(&_p) + } + totalj := <-chChunks[j] + _p.add(&totalj) + } + + return p.unsafeFromJacExtended(&_p) +} + +// selector stores the index, mask and shifts needed to select bits from a scalar +// it is used during the multiExp algorithm or the batch scalar multiplication +type selector struct { + index uint64 // index in the multi-word scalar to select bits from + mask uint64 // mask (c-bit wide) + shift uint64 // shift needed to get our bits on low positions + + multiWordSelect bool // set to true if we need to select bits from 2 words (case where c doesn't divide 64) + maskHigh uint64 // same than mask, for index+1 + shiftHigh uint64 // same than shift, for index+1 +} + +// return number of chunks for a given window size c +// the last chunk may be bigger to accommodate a potential carry from the NAF decomposition +func computeNbChunks(c uint64) uint64 { + return (fr.Bits + c - 1) / c +} + +// return the last window size for a scalar; +// this last window should accommodate a carry (from the NAF decomposition) +// it can be == c if we have 1 available bit +// it can be > c if we have 0 available bit +// it can be < c if we have 2+ available bits +func lastC(c uint64) uint64 { + nbAvailableBits := (computeNbChunks(c) * c) - fr.Bits + return c + 1 - nbAvailableBits +} + +type chunkStat struct { + // relative weight of work compared to other chunks. 100.0 -> nominal weight. + weight float32 + + // percentage of bucket filled in the window; + ppBucketFilled float32 + nbBucketFilled int +} + +// partitionScalars compute, for each scalars over c-bit wide windows, nbChunk digits +// if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract +// 2^{c} to the current digit, making it negative. +// negative digits can be processed in a later step as adding -G into the bucket instead of G +// (computing -G is cheap, and this saves us half of the buckets in the MultiExp or BatchScalarMultiplication) +func partitionScalars(scalars []fr.Element, c uint64, nbTasks int) ([]uint16, []chunkStat) { + // no benefit here to have more tasks than CPUs + if nbTasks > runtime.NumCPU() { + nbTasks = runtime.NumCPU() + } + + // number of c-bit radixes in a scalar + nbChunks := computeNbChunks(c) + + digits := make([]uint16, len(scalars)*int(nbChunks)) + + mask := uint64((1 << c) - 1) // low c bits are 1 + max := int(1<<(c-1)) - 1 // max value (inclusive) we want for our digits + cDivides64 := (64 % c) == 0 // if c doesn't divide 64, we may need to select over multiple words + + // compute offset and word selector / shift to select the right bits of our windows + selectors := make([]selector, nbChunks) + for chunk := uint64(0); chunk < nbChunks; chunk++ { + jc := uint64(chunk * c) + d := selector{} + d.index = jc / 64 + d.shift = jc - (d.index * 64) + d.mask = mask << d.shift + d.multiWordSelect = !cDivides64 && d.shift > (64-c) && d.index < (fr.Limbs-1) + if d.multiWordSelect { + nbBitsHigh := d.shift - uint64(64-c) + d.maskHigh = (1 << nbBitsHigh) - 1 + d.shiftHigh = (c - nbBitsHigh) + } + selectors[chunk] = d + } + + parallel.Execute(len(scalars), func(start, end int) { + for i := start; i < end; i++ { + if scalars[i].IsZero() { + // everything is 0, no need to process this scalar + continue + } + scalar := scalars[i].Bits() + + var carry int + + // for each chunk in the scalar, compute the current digit, and an eventual carry + for chunk := uint64(0); chunk < nbChunks-1; chunk++ { + s := selectors[chunk] + + // init with carry if any + digit := carry + carry = 0 + + // digit = value of the c-bit window + digit += int((scalar[s.index] & s.mask) >> s.shift) + + if s.multiWordSelect { + // we are selecting bits over 2 words + digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh + } + + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + if digit > max { + digit -= (1 << c) + carry = 1 + } + + // if digit is zero, no impact on result + if digit == 0 { + continue + } + + var bits uint16 + if digit > 0 { + bits = uint16(digit) << 1 + } else { + bits = (uint16(-digit-1) << 1) + 1 + } + digits[int(chunk)*len(scalars)+i] = bits + } + + // for the last chunk, we don't want to borrow from a next window + // (but may have a larger max value) + chunk := nbChunks - 1 + s := selectors[chunk] + // init with carry if any + digit := carry + // digit = value of the c-bit window + digit += int((scalar[s.index] & s.mask) >> s.shift) + if s.multiWordSelect { + // we are selecting bits over 2 words + digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh + } + digits[int(chunk)*len(scalars)+i] = uint16(digit) << 1 + } + + }, nbTasks) + + // aggregate chunk stats + chunkStats := make([]chunkStat, nbChunks) + if c <= 9 { + // no need to compute stats for small window sizes + return digits, chunkStats + } + parallel.Execute(len(chunkStats), func(start, end int) { + // for each chunk compute the statistics + for chunkID := start; chunkID < end; chunkID++ { + // indicates if a bucket is hit. + var b bitSetC16 + + // digits for the chunk + chunkDigits := digits[chunkID*len(scalars) : (chunkID+1)*len(scalars)] + + totalOps := 0 + nz := 0 // non zero buckets count + for _, digit := range chunkDigits { + if digit == 0 { + continue + } + totalOps++ + bucketID := digit >> 1 + if digit&1 == 0 { + bucketID -= 1 + } + if !b[bucketID] { + nz++ + b[bucketID] = true + } + } + chunkStats[chunkID].weight = float32(totalOps) // count number of ops for now, we will compute the weight after + chunkStats[chunkID].ppBucketFilled = (float32(nz) * 100.0) / float32(int(1<<(c-1))) + chunkStats[chunkID].nbBucketFilled = nz + } + }, nbTasks) + + totalOps := float32(0.0) + for _, stat := range chunkStats { + totalOps += stat.weight + } + + target := totalOps / float32(nbChunks) + if target != 0.0 { + // if target == 0, it means all the scalars are 0 everywhere, there is no work to be done. + for i := 0; i < len(chunkStats); i++ { + chunkStats[i].weight = (chunkStats[i].weight * 100.0) / target + } + } + + return digits, chunkStats +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_affine.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_affine.go new file mode 100644 index 00000000000..937a43c9d17 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_affine.go @@ -0,0 +1,710 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" +) + +type batchOpG1Affine struct { + bucketID uint16 + point G1Affine +} + +// processChunkG1BatchAffine process a chunk of the scalars during the msm +// using affine coordinates for the buckets. To amortize the cost of the inverse in the affine addition +// we use a batch affine addition. +// +// this is derived from a PR by 0x0ece : https://github.com/ConsenSys/gnark-crypto/pull/249 +// See Section 5.3: ia.cr/2022/1396 +func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP pG1Affine, TPP ppG1Affine, TQ qOpsG1Affine, TC cG1Affine]( + chunk uint64, + chRes chan<- g1JacExtended, + c uint64, + points []G1Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + // the batch affine addition needs independent points; in other words, for a window of batchSize + // we want to hit independent bucketIDs when processing the digit. if there is a conflict (we're trying + // to add 2 different points to the same bucket), then we push the conflicted point to a queue. + // each time the batch is full, we execute it, and tentatively put the points (if not conflict) + // from the top of the queue into the next batch. + // if the queue is full, we "flush it"; we sequentially add the points to the buckets in + // g1JacExtended coordinates. + // The reasoning behind this is the following; batchSize is chosen such as, for a uniformly random + // input, the number of conflicts is going to be low, and the element added to the queue should be immediately + // processed in the next batch. If it's not the case, then our inputs are not random; and we fallback to + // non-batch-affine version. + + // note that we have 2 sets of buckets + // 1 in G1Affine used with the batch affine additions + // 1 in g1JacExtended used in case the queue of conflicting points + var buckets B + var bucketsJE BJE + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + bucketsJE[i].setInfinity() + } + + // setup for the batch affine; + var ( + bucketIds BS // bitSet to signify presence of a bucket in current batch + cptAdd int // count the number of bucket + point added to current batch + R TPP // bucket references + P TP // points to be added to R (buckets); it is beneficial to store them on the stack (ie copy) + queue TQ // queue of points that conflict the current batch + qID int // current position in queue + ) + + batchSize := len(P) + + isFull := func() bool { return cptAdd == batchSize } + + executeAndReset := func() { + batchAddG1Affine[TP, TPP, TC](&R, &P, cptAdd) + var tmp BS + bucketIds = tmp + cptAdd = 0 + } + + addFromQueue := func(op batchOpG1Affine) { + // @precondition: must ensures bucket is not "used" in current batch + // note that there is a bit of duplicate logic between add and addFromQueue + // the reason is that as of Go 1.19.3, if we pass a pointer to the queue item (see add signature) + // the compiler will put the queue on the heap. + BK := &buckets[op.bucketID] + + // handle special cases with inf or -P / P + if BK.IsInfinity() { + BK.Set(&op.point) + return + } + if BK.X.Equal(&op.point.X) { + if BK.Y.Equal(&op.point.Y) { + // P + P: doubling, which should be quite rare -- + // we use the other set of buckets + bucketsJE[op.bucketID].addMixed(&op.point) + return + } + BK.setInfinity() + return + } + + bucketIds[op.bucketID] = true + R[cptAdd] = BK + P[cptAdd] = op.point + cptAdd++ + } + + add := func(bucketID uint16, PP *G1Affine, isAdd bool) { + // @precondition: ensures bucket is not "used" in current batch + BK := &buckets[bucketID] + // handle special cases with inf or -P / P + if BK.IsInfinity() { + if isAdd { + BK.Set(PP) + } else { + BK.Neg(PP) + } + return + } + if BK.X.Equal(&PP.X) { + if BK.Y.Equal(&PP.Y) { + // P + P: doubling, which should be quite rare -- + if isAdd { + bucketsJE[bucketID].addMixed(PP) + } else { + BK.setInfinity() + } + return + } + if isAdd { + BK.setInfinity() + } else { + bucketsJE[bucketID].subMixed(PP) + } + return + } + + bucketIds[bucketID] = true + R[cptAdd] = BK + if isAdd { + P[cptAdd].Set(PP) + } else { + P[cptAdd].Neg(PP) + } + cptAdd++ + } + + flushQueue := func() { + for i := 0; i < qID; i++ { + bucketsJE[queue[i].bucketID].addMixed(&queue[i].point) + } + qID = 0 + } + + processTopQueue := func() { + for i := qID - 1; i >= 0; i-- { + if bucketIds[queue[i].bucketID] { + return + } + addFromQueue(queue[i]) + // len(queue) < batchSize so no need to check for full batch. + qID-- + } + } + + for i, digit := range digits { + + if digit == 0 || points[i].IsInfinity() { + continue + } + + bucketID := uint16((digit >> 1)) + isAdd := digit&1 == 0 + if isAdd { + // add + bucketID -= 1 + } + + if bucketIds[bucketID] { + // put it in queue + queue[qID].bucketID = bucketID + if isAdd { + queue[qID].point.Set(&points[i]) + } else { + queue[qID].point.Neg(&points[i]) + } + qID++ + + // queue is full, flush it. + if qID == len(queue)-1 { + flushQueue() + } + continue + } + + // we add the point to the batch. + add(bucketID, &points[i], isAdd) + if isFull() { + executeAndReset() + processTopQueue() + } + } + + // flush items in batch. + executeAndReset() + + // empty the queue + flushQueue() + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + var runningSum, total g1JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + runningSum.addMixed(&buckets[k]) + if !bucketsJE[k].IsZero() { + runningSum.add(&bucketsJE[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total + +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketG1AffineC10 [512]G1Affine +type bucketG1AffineC11 [1024]G1Affine +type bucketG1AffineC12 [2048]G1Affine +type bucketG1AffineC13 [4096]G1Affine +type bucketG1AffineC14 [8192]G1Affine +type bucketG1AffineC15 [16384]G1Affine +type bucketG1AffineC16 [32768]G1Affine + +// buckets: array of G1Affine points of size 1 << (c-1) +type ibG1Affine interface { + bucketG1AffineC10 | + bucketG1AffineC11 | + bucketG1AffineC12 | + bucketG1AffineC13 | + bucketG1AffineC14 | + bucketG1AffineC15 | + bucketG1AffineC16 +} + +// array of coordinates fp.Element +type cG1Affine interface { + cG1AffineC10 | + cG1AffineC11 | + cG1AffineC12 | + cG1AffineC13 | + cG1AffineC14 | + cG1AffineC15 | + cG1AffineC16 +} + +// buckets: array of G1Affine points (for the batch addition) +type pG1Affine interface { + pG1AffineC10 | + pG1AffineC11 | + pG1AffineC12 | + pG1AffineC13 | + pG1AffineC14 | + pG1AffineC15 | + pG1AffineC16 +} + +// buckets: array of *G1Affine points (for the batch addition) +type ppG1Affine interface { + ppG1AffineC10 | + ppG1AffineC11 | + ppG1AffineC12 | + ppG1AffineC13 | + ppG1AffineC14 | + ppG1AffineC15 | + ppG1AffineC16 +} + +// buckets: array of G1Affine queue operations (for the batch addition) +type qOpsG1Affine interface { + qG1AffineC10 | + qG1AffineC11 | + qG1AffineC12 | + qG1AffineC13 | + qG1AffineC14 | + qG1AffineC15 | + qG1AffineC16 +} + +// batch size 80 when c = 10 +type cG1AffineC10 [80]fp.Element +type pG1AffineC10 [80]G1Affine +type ppG1AffineC10 [80]*G1Affine +type qG1AffineC10 [80]batchOpG1Affine + +// batch size 150 when c = 11 +type cG1AffineC11 [150]fp.Element +type pG1AffineC11 [150]G1Affine +type ppG1AffineC11 [150]*G1Affine +type qG1AffineC11 [150]batchOpG1Affine + +// batch size 200 when c = 12 +type cG1AffineC12 [200]fp.Element +type pG1AffineC12 [200]G1Affine +type ppG1AffineC12 [200]*G1Affine +type qG1AffineC12 [200]batchOpG1Affine + +// batch size 350 when c = 13 +type cG1AffineC13 [350]fp.Element +type pG1AffineC13 [350]G1Affine +type ppG1AffineC13 [350]*G1Affine +type qG1AffineC13 [350]batchOpG1Affine + +// batch size 400 when c = 14 +type cG1AffineC14 [400]fp.Element +type pG1AffineC14 [400]G1Affine +type ppG1AffineC14 [400]*G1Affine +type qG1AffineC14 [400]batchOpG1Affine + +// batch size 500 when c = 15 +type cG1AffineC15 [500]fp.Element +type pG1AffineC15 [500]G1Affine +type ppG1AffineC15 [500]*G1Affine +type qG1AffineC15 [500]batchOpG1Affine + +// batch size 640 when c = 16 +type cG1AffineC16 [640]fp.Element +type pG1AffineC16 [640]G1Affine +type ppG1AffineC16 [640]*G1Affine +type qG1AffineC16 [640]batchOpG1Affine + +type batchOpG2Affine struct { + bucketID uint16 + point G2Affine +} + +// processChunkG2BatchAffine process a chunk of the scalars during the msm +// using affine coordinates for the buckets. To amortize the cost of the inverse in the affine addition +// we use a batch affine addition. +// +// this is derived from a PR by 0x0ece : https://github.com/ConsenSys/gnark-crypto/pull/249 +// See Section 5.3: ia.cr/2022/1396 +func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP pG2Affine, TPP ppG2Affine, TQ qOpsG2Affine, TC cG2Affine]( + chunk uint64, + chRes chan<- g2JacExtended, + c uint64, + points []G2Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + // the batch affine addition needs independent points; in other words, for a window of batchSize + // we want to hit independent bucketIDs when processing the digit. if there is a conflict (we're trying + // to add 2 different points to the same bucket), then we push the conflicted point to a queue. + // each time the batch is full, we execute it, and tentatively put the points (if not conflict) + // from the top of the queue into the next batch. + // if the queue is full, we "flush it"; we sequentially add the points to the buckets in + // g2JacExtended coordinates. + // The reasoning behind this is the following; batchSize is chosen such as, for a uniformly random + // input, the number of conflicts is going to be low, and the element added to the queue should be immediately + // processed in the next batch. If it's not the case, then our inputs are not random; and we fallback to + // non-batch-affine version. + + // note that we have 2 sets of buckets + // 1 in G2Affine used with the batch affine additions + // 1 in g2JacExtended used in case the queue of conflicting points + var buckets B + var bucketsJE BJE + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + bucketsJE[i].setInfinity() + } + + // setup for the batch affine; + var ( + bucketIds BS // bitSet to signify presence of a bucket in current batch + cptAdd int // count the number of bucket + point added to current batch + R TPP // bucket references + P TP // points to be added to R (buckets); it is beneficial to store them on the stack (ie copy) + queue TQ // queue of points that conflict the current batch + qID int // current position in queue + ) + + batchSize := len(P) + + isFull := func() bool { return cptAdd == batchSize } + + executeAndReset := func() { + batchAddG2Affine[TP, TPP, TC](&R, &P, cptAdd) + var tmp BS + bucketIds = tmp + cptAdd = 0 + } + + addFromQueue := func(op batchOpG2Affine) { + // @precondition: must ensures bucket is not "used" in current batch + // note that there is a bit of duplicate logic between add and addFromQueue + // the reason is that as of Go 1.19.3, if we pass a pointer to the queue item (see add signature) + // the compiler will put the queue on the heap. + BK := &buckets[op.bucketID] + + // handle special cases with inf or -P / P + if BK.IsInfinity() { + BK.Set(&op.point) + return + } + if BK.X.Equal(&op.point.X) { + if BK.Y.Equal(&op.point.Y) { + // P + P: doubling, which should be quite rare -- + // we use the other set of buckets + bucketsJE[op.bucketID].addMixed(&op.point) + return + } + BK.setInfinity() + return + } + + bucketIds[op.bucketID] = true + R[cptAdd] = BK + P[cptAdd] = op.point + cptAdd++ + } + + add := func(bucketID uint16, PP *G2Affine, isAdd bool) { + // @precondition: ensures bucket is not "used" in current batch + BK := &buckets[bucketID] + // handle special cases with inf or -P / P + if BK.IsInfinity() { + if isAdd { + BK.Set(PP) + } else { + BK.Neg(PP) + } + return + } + if BK.X.Equal(&PP.X) { + if BK.Y.Equal(&PP.Y) { + // P + P: doubling, which should be quite rare -- + if isAdd { + bucketsJE[bucketID].addMixed(PP) + } else { + BK.setInfinity() + } + return + } + if isAdd { + BK.setInfinity() + } else { + bucketsJE[bucketID].subMixed(PP) + } + return + } + + bucketIds[bucketID] = true + R[cptAdd] = BK + if isAdd { + P[cptAdd].Set(PP) + } else { + P[cptAdd].Neg(PP) + } + cptAdd++ + } + + flushQueue := func() { + for i := 0; i < qID; i++ { + bucketsJE[queue[i].bucketID].addMixed(&queue[i].point) + } + qID = 0 + } + + processTopQueue := func() { + for i := qID - 1; i >= 0; i-- { + if bucketIds[queue[i].bucketID] { + return + } + addFromQueue(queue[i]) + // len(queue) < batchSize so no need to check for full batch. + qID-- + } + } + + for i, digit := range digits { + + if digit == 0 || points[i].IsInfinity() { + continue + } + + bucketID := uint16((digit >> 1)) + isAdd := digit&1 == 0 + if isAdd { + // add + bucketID -= 1 + } + + if bucketIds[bucketID] { + // put it in queue + queue[qID].bucketID = bucketID + if isAdd { + queue[qID].point.Set(&points[i]) + } else { + queue[qID].point.Neg(&points[i]) + } + qID++ + + // queue is full, flush it. + if qID == len(queue)-1 { + flushQueue() + } + continue + } + + // we add the point to the batch. + add(bucketID, &points[i], isAdd) + if isFull() { + executeAndReset() + processTopQueue() + } + } + + // flush items in batch. + executeAndReset() + + // empty the queue + flushQueue() + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + var runningSum, total g2JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + runningSum.addMixed(&buckets[k]) + if !bucketsJE[k].IsZero() { + runningSum.add(&bucketsJE[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total + +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketG2AffineC10 [512]G2Affine +type bucketG2AffineC11 [1024]G2Affine +type bucketG2AffineC12 [2048]G2Affine +type bucketG2AffineC13 [4096]G2Affine +type bucketG2AffineC14 [8192]G2Affine +type bucketG2AffineC15 [16384]G2Affine +type bucketG2AffineC16 [32768]G2Affine + +// buckets: array of G2Affine points of size 1 << (c-1) +type ibG2Affine interface { + bucketG2AffineC10 | + bucketG2AffineC11 | + bucketG2AffineC12 | + bucketG2AffineC13 | + bucketG2AffineC14 | + bucketG2AffineC15 | + bucketG2AffineC16 +} + +// array of coordinates fptower.E2 +type cG2Affine interface { + cG2AffineC10 | + cG2AffineC11 | + cG2AffineC12 | + cG2AffineC13 | + cG2AffineC14 | + cG2AffineC15 | + cG2AffineC16 +} + +// buckets: array of G2Affine points (for the batch addition) +type pG2Affine interface { + pG2AffineC10 | + pG2AffineC11 | + pG2AffineC12 | + pG2AffineC13 | + pG2AffineC14 | + pG2AffineC15 | + pG2AffineC16 +} + +// buckets: array of *G2Affine points (for the batch addition) +type ppG2Affine interface { + ppG2AffineC10 | + ppG2AffineC11 | + ppG2AffineC12 | + ppG2AffineC13 | + ppG2AffineC14 | + ppG2AffineC15 | + ppG2AffineC16 +} + +// buckets: array of G2Affine queue operations (for the batch addition) +type qOpsG2Affine interface { + qG2AffineC10 | + qG2AffineC11 | + qG2AffineC12 | + qG2AffineC13 | + qG2AffineC14 | + qG2AffineC15 | + qG2AffineC16 +} + +// batch size 80 when c = 10 +type cG2AffineC10 [80]fptower.E2 +type pG2AffineC10 [80]G2Affine +type ppG2AffineC10 [80]*G2Affine +type qG2AffineC10 [80]batchOpG2Affine + +// batch size 150 when c = 11 +type cG2AffineC11 [150]fptower.E2 +type pG2AffineC11 [150]G2Affine +type ppG2AffineC11 [150]*G2Affine +type qG2AffineC11 [150]batchOpG2Affine + +// batch size 200 when c = 12 +type cG2AffineC12 [200]fptower.E2 +type pG2AffineC12 [200]G2Affine +type ppG2AffineC12 [200]*G2Affine +type qG2AffineC12 [200]batchOpG2Affine + +// batch size 350 when c = 13 +type cG2AffineC13 [350]fptower.E2 +type pG2AffineC13 [350]G2Affine +type ppG2AffineC13 [350]*G2Affine +type qG2AffineC13 [350]batchOpG2Affine + +// batch size 400 when c = 14 +type cG2AffineC14 [400]fptower.E2 +type pG2AffineC14 [400]G2Affine +type ppG2AffineC14 [400]*G2Affine +type qG2AffineC14 [400]batchOpG2Affine + +// batch size 500 when c = 15 +type cG2AffineC15 [500]fptower.E2 +type pG2AffineC15 [500]G2Affine +type ppG2AffineC15 [500]*G2Affine +type qG2AffineC15 [500]batchOpG2Affine + +// batch size 640 when c = 16 +type cG2AffineC16 [640]fptower.E2 +type pG2AffineC16 [640]G2Affine +type ppG2AffineC16 [640]*G2Affine +type qG2AffineC16 [640]batchOpG2Affine + +type bitSetC3 [4]bool +type bitSetC4 [8]bool +type bitSetC5 [16]bool +type bitSetC6 [32]bool +type bitSetC7 [64]bool +type bitSetC8 [128]bool +type bitSetC9 [256]bool +type bitSetC10 [512]bool +type bitSetC11 [1024]bool +type bitSetC12 [2048]bool +type bitSetC13 [4096]bool +type bitSetC14 [8192]bool +type bitSetC15 [16384]bool +type bitSetC16 [32768]bool + +type bitSet interface { + bitSetC3 | + bitSetC4 | + bitSetC5 | + bitSetC6 | + bitSetC7 | + bitSetC8 | + bitSetC9 | + bitSetC10 | + bitSetC11 | + bitSetC12 | + bitSetC13 | + bitSetC14 | + bitSetC15 | + bitSetC16 +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_jacobian.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_jacobian.go new file mode 100644 index 00000000000..1b8c0e79aa4 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp_jacobian.go @@ -0,0 +1,195 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bls12381 + +func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, + chRes chan<- g1JacExtended, + c uint64, + points []G1Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + var buckets B + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i, digit := range digits { + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + buckets[(digit>>1)-1].addMixed(&points[i]) + } else { + // sub + buckets[(digit >> 1)].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g1JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketg1JacExtendedC3 [4]g1JacExtended +type bucketg1JacExtendedC4 [8]g1JacExtended +type bucketg1JacExtendedC5 [16]g1JacExtended +type bucketg1JacExtendedC6 [32]g1JacExtended +type bucketg1JacExtendedC7 [64]g1JacExtended +type bucketg1JacExtendedC8 [128]g1JacExtended +type bucketg1JacExtendedC9 [256]g1JacExtended +type bucketg1JacExtendedC10 [512]g1JacExtended +type bucketg1JacExtendedC11 [1024]g1JacExtended +type bucketg1JacExtendedC12 [2048]g1JacExtended +type bucketg1JacExtendedC13 [4096]g1JacExtended +type bucketg1JacExtendedC14 [8192]g1JacExtended +type bucketg1JacExtendedC15 [16384]g1JacExtended +type bucketg1JacExtendedC16 [32768]g1JacExtended + +type ibg1JacExtended interface { + bucketg1JacExtendedC3 | + bucketg1JacExtendedC4 | + bucketg1JacExtendedC5 | + bucketg1JacExtendedC6 | + bucketg1JacExtendedC7 | + bucketg1JacExtendedC8 | + bucketg1JacExtendedC9 | + bucketg1JacExtendedC10 | + bucketg1JacExtendedC11 | + bucketg1JacExtendedC12 | + bucketg1JacExtendedC13 | + bucketg1JacExtendedC14 | + bucketg1JacExtendedC15 | + bucketg1JacExtendedC16 +} + +func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, + chRes chan<- g2JacExtended, + c uint64, + points []G2Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + var buckets B + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i, digit := range digits { + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + buckets[(digit>>1)-1].addMixed(&points[i]) + } else { + // sub + buckets[(digit >> 1)].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g2JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketg2JacExtendedC3 [4]g2JacExtended +type bucketg2JacExtendedC4 [8]g2JacExtended +type bucketg2JacExtendedC5 [16]g2JacExtended +type bucketg2JacExtendedC6 [32]g2JacExtended +type bucketg2JacExtendedC7 [64]g2JacExtended +type bucketg2JacExtendedC8 [128]g2JacExtended +type bucketg2JacExtendedC9 [256]g2JacExtended +type bucketg2JacExtendedC10 [512]g2JacExtended +type bucketg2JacExtendedC11 [1024]g2JacExtended +type bucketg2JacExtendedC12 [2048]g2JacExtended +type bucketg2JacExtendedC13 [4096]g2JacExtended +type bucketg2JacExtendedC14 [8192]g2JacExtended +type bucketg2JacExtendedC15 [16384]g2JacExtended +type bucketg2JacExtendedC16 [32768]g2JacExtended + +type ibg2JacExtended interface { + bucketg2JacExtendedC3 | + bucketg2JacExtendedC4 | + bucketg2JacExtendedC5 | + bucketg2JacExtendedC6 | + bucketg2JacExtendedC7 | + bucketg2JacExtendedC8 | + bucketg2JacExtendedC9 | + bucketg2JacExtendedC10 | + bucketg2JacExtendedC11 | + bucketg2JacExtendedC12 | + bucketg2JacExtendedC13 | + bucketg2JacExtendedC14 | + bucketg2JacExtendedC15 | + bucketg2JacExtendedC16 +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/pairing.go new file mode 100644 index 00000000000..e2c362f9b51 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/pairing.go @@ -0,0 +1,347 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package bls12381 + +import ( + "errors" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" +) + +// GT target group of the pairing +type GT = fptower.E12 + +type lineEvaluation struct { + r0 fptower.E2 + r1 fptower.E2 + r2 fptower.E2 +} + +// Pair calculates the reduced pairing for a set of points +// ∏ᵢ e(Pᵢ, Qᵢ). +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. +func Pair(P []G1Affine, Q []G2Affine) (GT, error) { + f, err := MillerLoop(P, Q) + if err != nil { + return GT{}, err + } + return FinalExponentiation(&f), nil +} + +// PairingCheck calculates the reduced pairing for a set of points and returns True if the result is One +// ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. +func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) { + f, err := Pair(P, Q) + if err != nil { + return false, err + } + var one GT + one.SetOne() + return f.Equal(&one), nil +} + +// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ +// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// where s is the cofactor 3 (Hayashida et al.) +func FinalExponentiation(z *GT, _z ...*GT) GT { + var result GT + result.Set(z) + + for _, e := range _z { + result.Mul(&result, e) + } + + var t [3]GT + + // Easy part + // (p⁶-1)(p²+1) + t[0].Conjugate(&result) + result.Inverse(&result) + t[0].Mul(&t[0], &result) + result.FrobeniusSquare(&t[0]). + Mul(&result, &t[0]) + + var one GT + one.SetOne() + if result.Equal(&one) { + return result + } + + // Hard part (up to permutation) + // Daiki Hayashida, Kenichiro Hayasaka and Tadanori Teruya + // https://eprint.iacr.org/2020/875.pdf + t[0].CyclotomicSquare(&result) + t[1].ExptHalf(&t[0]) + t[2].InverseUnitary(&result) + t[1].Mul(&t[1], &t[2]) + t[2].Expt(&t[1]) + t[1].InverseUnitary(&t[1]) + t[1].Mul(&t[1], &t[2]) + t[2].Expt(&t[1]) + t[1].Frobenius(&t[1]) + t[1].Mul(&t[1], &t[2]) + result.Mul(&result, &t[0]) + t[0].Expt(&t[1]) + t[2].Expt(&t[0]) + t[0].FrobeniusSquare(&t[1]) + t[1].InverseUnitary(&t[1]) + t[1].Mul(&t[1], &t[2]) + t[1].Mul(&t[1], &t[0]) + result.Mul(&result, &t[1]) + + return result +} + +// MillerLoop computes the multi-Miller loop +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = ∏ᵢ { fᵢ_{x,Qᵢ}(Pᵢ) } +func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { + // check input size match + n := len(P) + if n == 0 || n != len(Q) { + return GT{}, errors.New("invalid inputs sizes") + } + + // filter infinity points + p := make([]G1Affine, 0, n) + q := make([]G2Affine, 0, n) + + for k := 0; k < n; k++ { + if P[k].IsInfinity() || Q[k].IsInfinity() { + continue + } + p = append(p, P[k]) + q = append(q, Q[k]) + } + + n = len(p) + + // projective points for Q + qProj := make([]g2Proj, n) + for k := 0; k < n; k++ { + qProj[k].FromAffine(&q[k]) + } + + var result GT + result.SetOne() + var l1, l2 lineEvaluation + var prodLines [5]E2 + + // Compute ∏ᵢ { fᵢ_{x₀,Q}(P) } + if n >= 1 { + // i = 62, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[62] = 1 + // k = 0, separately to avoid MulBy014 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] + qProj[0].doubleStep(&l1) + // line evaluation at P[0] (assign) + result.C0.B0.Set(&l1.r0) + result.C0.B1.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.MulByElement(&l1.r2, &p[0].Y) + + // qProj[0] ← qProj[0]+Q[0] and + // l2 the line ℓ passing qProj[0] and Q[0] + qProj[0].addMixedStep(&l2, &q[0]) + // line evaluation at P[0] (assign) + l2.r1.MulByElement(&l2.r1, &p[0].X) + l2.r2.MulByElement(&l2.r2, &p[0].Y) + // ℓ × res + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &result.C0.B0, &result.C0.B1, &result.C1.B1) + result.C0.B0 = prodLines[0] + result.C0.B1 = prodLines[1] + result.C0.B2 = prodLines[2] + result.C1.B1 = prodLines[3] + result.C1.B2 = prodLines[4] + } + + // k >= 1 + for k := 1; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] + qProj[k].doubleStep(&l1) + // line evaluation at P[k] + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) + + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] + qProj[k].addMixedStep(&l2, &q[k]) + // line evaluation at P[k] + l2.r1.MulByElement(&l2.r1, &p[k].X) + l2.r2.MulByElement(&l2.r2, &p[k].Y) + // ℓ × ℓ + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) + // (ℓ × ℓ) × result + result.MulBy01245(&prodLines) + } + + // i <= 61 + for i := len(loopCounter) - 3; i >= 1; i-- { + // mutualize the square among n Miller loops + // (∏ᵢfᵢ)² + result.Square(&result) + + for k := 0; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] + qProj[k].doubleStep(&l1) + // line evaluation at P[k] + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) + + if loopCounter[i] == 0 { + // ℓ × res + result.MulBy014(&l1.r0, &l1.r1, &l1.r2) + } else { + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] + qProj[k].addMixedStep(&l2, &q[k]) + // line evaluation at P[k] + l2.r1.MulByElement(&l2.r1, &p[k].X) + l2.r2.MulByElement(&l2.r2, &p[k].Y) + // ℓ × ℓ + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) + // (ℓ × ℓ) × result + result.MulBy01245(&prodLines) + } + } + } + + // i = 0, separately to avoid a point doubling + // loopCounter[0] = 0 + result.Square(&result) + for k := 0; k < n; k++ { + // l1 the tangent ℓ passing 2qProj[k] + qProj[k].tangentLine(&l1) + // line evaluation at P[k] + l1.r1.MulByElement(&l1.r1, &p[k].X) + l1.r2.MulByElement(&l1.r2, &p[k].Y) + // ℓ × result + result.MulBy014(&l1.r0, &l1.r1, &l1.r2) + } + + // negative x₀ + result.Conjugate(&result) + + return result, nil +} + +// doubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop +// https://eprint.iacr.org/2013/722.pdf (Section 4.3) +func (p *g2Proj) doubleStep(l *lineEvaluation) { + + // get some Element from our pool + var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 + A.Mul(&p.x, &p.y) + A.Halve() + B.Square(&p.y) + C.Square(&p.z) + D.Double(&C). + Add(&D, &C) + E.MulBybTwistCurveCoeff(&D) + F.Double(&E). + Add(&F, &E) + G.Add(&B, &F) + G.Halve() + H.Add(&p.y, &p.z). + Square(&H) + t1.Add(&B, &C) + H.Sub(&H, &t1) + I.Sub(&E, &B) + J.Square(&p.x) + EE.Square(&E) + K.Double(&EE). + Add(&K, &EE) + + // X, Y, Z + p.x.Sub(&B, &F). + Mul(&p.x, &A) + p.y.Square(&G). + Sub(&p.y, &K) + p.z.Mul(&B, &H) + + // Line evaluation + l.r0.Set(&I) + l.r1.Double(&J). + Add(&l.r1, &J) + l.r2.Neg(&H) + +} + +// addMixedStep point addition in Mixed Homogenous projective and Affine coordinates +// https://eprint.iacr.org/2013/722.pdf (Section 4.3) +func (p *g2Proj) addMixedStep(l *lineEvaluation, a *G2Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 + Y2Z1.Mul(&a.Y, &p.z) + O.Sub(&p.y, &Y2Z1) + X2Z1.Mul(&a.X, &p.z) + L.Sub(&p.x, &X2Z1) + C.Square(&O) + D.Square(&L) + E.Mul(&L, &D) + F.Mul(&p.z, &C) + G.Mul(&p.x, &D) + t0.Double(&G) + H.Add(&E, &F). + Sub(&H, &t0) + t1.Mul(&p.y, &E) + + // X, Y, Z + p.x.Mul(&L, &H) + p.y.Sub(&G, &H). + Mul(&p.y, &O). + Sub(&p.y, &t1) + p.z.Mul(&E, &p.z) + + t2.Mul(&L, &a.Y) + J.Mul(&a.X, &O). + Sub(&J, &t2) + + // Line evaluation + l.r0.Set(&J) + l.r1.Neg(&O) + l.r2.Set(&L) +} + +// tangentCompute computes the tangent through [2]p in Homogenous projective coordinates. +// It does not compute the resulting point [2]p. +func (p *g2Proj) tangentLine(l *lineEvaluation) { + + // get some Element from our pool + var t1, B, C, D, E, H, I, J fptower.E2 + B.Square(&p.y) + C.Square(&p.z) + D.Double(&C). + Add(&D, &C) + E.MulBybTwistCurveCoeff(&D) + H.Add(&p.y, &p.z). + Square(&H) + t1.Add(&B, &C) + H.Sub(&H, &t1) + I.Sub(&E, &B) + J.Square(&p.x) + + // Line evaluation + l.r0.Set(&I) + l.r1.Double(&J). + Add(&l.r1, &J) + l.r2.Neg(&H) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/bn254.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/bn254.go index c476c70ab0d..f6f2990ca39 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/bn254.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/bn254.go @@ -1,3 +1,45 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package bn254 efficient elliptic curve, pairing and hash to curve implementation for bn254. This curve appears in +// Ethereum pre-compiles as altbn128. +// +// bn254: A Barreto--Naerig curve with +// +// seed x₀=4965661367192848881 +// 𝔽r: r=21888242871839275222246405745257275088548364400416034343698204186575808495617 (36x₀⁴+36x₀³+18x₀²+6x₀+1) +// 𝔽p: p=21888242871839275222246405745257275088696311157297823662689037894645226208583 (36x₀⁴+36x₀³+24x₀²+6x₀+1) +// (E/𝔽p): Y²=X³+3 +// (Eₜ/𝔽p²): Y² = X³+3/(u+9) (D-type twist) +// r ∣ #E(Fp) and r ∣ #Eₜ(𝔽p²) +// +// Extension fields tower: +// +// 𝔽p²[u] = 𝔽p/u²+1 +// 𝔽p⁶[v] = 𝔽p²/v³-9-u +// 𝔽p¹²[w] = 𝔽p⁶/w²-v +// +// optimal Ate loop size: +// +// 6x₀+2 +// +// Security: estimated 103-bit level following [https://eprint.iacr.org/2019/885.pdf] +// (r is 254 bits and p¹² is 3044 bits) +// +// # Warning +// +// This code has been partially audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. package bn254 import ( @@ -9,25 +51,17 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" ) -// E: y**2=x**3+3 -// Etwist: y**2 = x**3+3*(u+9)**-1 -// Tower: Fp->Fp2, u**2=-1 -> Fp12, v**6=9+u -// Generator (BN family): x=4965661367192848881 -// optimal Ate loop: 6x+2 -// trace of pi: x+1 -// Fp: p=21888242871839275222246405745257275088696311157297823662689037894645226208583 -// Fr: r=21888242871839275222246405745257275088548364400416034343698204186575808495617 - // ID bn254 ID const ID = ecc.BN254 -// bCurveCoeff b coeff of the curve +// aCurveCoeff is the a coefficients of the curve Y²=X³+ax+b +var aCurveCoeff fp.Element var bCurveCoeff fp.Element // twist var twist fptower.E2 -// bTwistCurveCoeff b coeff of the twist (defined over Fp2) curve +// bTwistCurveCoeff b coeff of the twist (defined over 𝔽p²) curve var bTwistCurveCoeff fptower.E2 // generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) @@ -45,40 +79,49 @@ var g2Infinity G2Jac var loopCounter [66]int8 // Parameters useful for the GLV scalar multiplication. The third roots define the -// endomorphisms phi1 and phi2 for and . lambda is such that lies above -// in the ring Z[phi]. More concretely it's the associated eigenvalue -// of phi1 (resp phi2) restricted to (resp ) -// cf https://www.cosic.esat.kuleuven.be/nessie/reports/phase2/GLV.pdf +// endomorphisms ϕ₁ and ϕ₂ for and . lambda is such that lies above +// in the ring Z[ϕ]. More concretely it's the associated eigenvalue +// of ϕ₁ (resp ϕ₂) restricted to (resp ) +// see https://www.cosic.esat.kuleuven.be/nessie/reports/phase2/GLV.pdf var thirdRootOneG1 fp.Element var thirdRootOneG2 fp.Element var lambdaGLV big.Int -// glvBasis stores R-linearly independant vectors (a,b), (c,d) -// in ker((u,v)->u+vlambda[r]), and their determinant +// glvBasis stores R-linearly independent vectors (a,b), (c,d) +// in ker((u,v) → u+vλ[r]), and their determinant var glvBasis ecc.Lattice -// psi o pi o psi**-1, where psi:E->E' is the degree 6 iso defined over Fp12 +// ψ o π o ψ⁻¹, where ψ:E → E' is the degree 6 iso defined over 𝔽p¹² var endo struct { u fptower.E2 v fptower.E2 } -// generator of the curve +// seed x₀ of the curve var xGen big.Int -// fixefCoeff t-1 = 6*xGen^2 -var fixedCoeff big.Int +// expose the tower -- github.com/consensys/gnark uses it in a gnark circuit -func init() { +// 𝔽p² +type E2 = fptower.E2 + +// 𝔽p⁶ +type E6 = fptower.E6 + +// 𝔽p¹² +type E12 = fptower.E12 +func init() { + aCurveCoeff.SetUint64(0) bCurveCoeff.SetUint64(3) + // D-twist twist.A0.SetUint64(9) twist.A1.SetUint64(1) bTwistCurveCoeff.Inverse(&twist).MulByElement(&bTwistCurveCoeff, &bCurveCoeff) - g1Gen.X.SetString("1") - g1Gen.Y.SetString("2") - g1Gen.Z.SetString("1") + g1Gen.X.SetOne() + g1Gen.Y.SetUint64(2) + g1Gen.Z.SetOne() g2Gen.X.SetString("10857046999023057135944570762232829481370756359578518086990519993285655852781", "11559732032986387107991004021392285783925812861821192530917403151452391805634") @@ -90,6 +133,7 @@ func init() { g1GenAff.FromJacobian(&g1Gen) g2GenAff.FromJacobian(&g2Gen) + // (X,Y,Z) = (1,1,0) g1Infinity.X.SetOne() g1Infinity.Y.SetOne() g2Infinity.X.SetOne() @@ -97,7 +141,7 @@ func init() { thirdRootOneG1.SetString("2203960485148121921418603742825762020974279258880205651966") thirdRootOneG2.Square(&thirdRootOneG1) - lambdaGLV.SetString("4407920970296243842393367215006156084916469457145843978461", 10) // (36*x**3+18*x**2+6*x+1) + lambdaGLV.SetString("4407920970296243842393367215006156084916469457145843978461", 10) // (36x₀³+18x₀²+6x₀+1) _r := fr.Modulus() ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) @@ -106,14 +150,12 @@ func init() { endo.v.A0.SetString("2821565182194536844548159561693502659359617185244120367078079554186484126554") endo.v.A1.SetString("3505843767911556378687030309984248845540243509899259641013678093033130930403") - // binary decomposition of 15132376222941642752 little endian + // 2-NAF decomposition of 6x₀+2 little endian optimaAteLoop, _ := new(big.Int).SetString("29793968203157093288", 10) ecc.NafDecomposition(optimaAteLoop, loopCounter[:]) xGen.SetString("4965661367192848881", 10) - fixedCoeff.SetString("147946756881789318990833708069417712966", 10) - } // Generators return the generators of the r-torsion group, resp. in ker(pi-id), ker(Tr) @@ -124,3 +166,8 @@ func Generators() (g1Jac G1Jac, g2Jac G2Jac, g1Aff G1Affine, g2Aff G2Affine) { g2Jac = g2Gen return } + +// CurveCoefficients returns the a, b coefficients of the curve equation. +func CurveCoefficients() (a, b fp.Element) { + return aCurveCoeff, bCurveCoeff +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/arith.go index 66fa667482a..6f281563b3d 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/arith.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/arith.go @@ -58,3 +58,16 @@ func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { hi, _ = bits.Add64(hi, e, carry) return } +func max(a int, b int) int { + if a > b { + return a + } + return b +} + +func min(a int, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm.go index 7344271ebee..0481989ec6a 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm.go @@ -21,4 +21,7 @@ package fp import "golang.org/x/sys/cpu" -var supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm_noadx.go index ae778bd3a1f..92f8cc0f424 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm_noadx.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/asm_noadx.go @@ -22,4 +22,7 @@ package fp // note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag // certain errors (like fatal error: missing stackmap) // this ensures we test all asm path. -var supportAdx = false +var ( + supportAdx = false + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/doc.go index 7961440127d..ac24d2e0de5 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/doc.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/doc.go @@ -21,23 +21,33 @@ // The modulus is hardcoded in all the operations. // // Field elements are represented as an array, and assumed to be in Montgomery form in all methods: -// type Element [4]uint64 // -// Example API signature -// // Mul z = x * y mod q -// func (z *Element) Mul(x, y *Element) *Element +// type Element [4]uint64 +// +// # Usage +// +// Example API signature: +// +// // Mul z = x * y (mod q) +// func (z *Element) Mul(x, y *Element) *Element // // and can be used like so: -// var a, b Element -// a.SetUint64(2) -// b.SetString("984896738") -// a.Mul(a, b) -// a.Sub(a, a) -// .Add(a, b) -// .Inv(a) -// b.Exp(b, new(big.Int).SetUint64(42)) -// -// Modulus -// 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 // base 16 -// 21888242871839275222246405745257275088696311157297823662689037894645226208583 // base 10 +// +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus q = +// +// q[base10] = 21888242871839275222246405745257275088696311157297823662689037894645226208583 +// q[base16] = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. package fp diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element.go index 0c5e5a20c88..5ba388e7376 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element.go @@ -16,12 +16,6 @@ package fp -// /!\ WARNING /!\ -// this code has not been audited and is provided as-is. In particular, -// there is no security guarantees such as constant time implementation -// or side-channel attack resistance -// /!\ WARNING /!\ - import ( "crypto/rand" "encoding/binary" @@ -32,75 +26,71 @@ import ( "reflect" "strconv" "strings" - "sync" + + "github.com/bits-and-blooms/bitset" + "github.com/consensys/gnark-crypto/field/hash" + "github.com/consensys/gnark-crypto/field/pool" ) // Element represents a field element stored on 4 words (uint64) -// Element are assumed to be in Montgomery form in all methods -// field modulus q = // -// 21888242871839275222246405745257275088696311157297823662689037894645226208583 +// Element are assumed to be in Montgomery form in all methods. +// +// Modulus q = +// +// q[base10] = 21888242871839275222246405745257275088696311157297823662689037894645226208583 +// q[base16] = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. type Element [4]uint64 -// Limbs number of 64 bits words needed to represent Element -const Limbs = 4 +const ( + Limbs = 4 // number of 64 bits words needed to represent a Element + Bits = 254 // number of bits needed to represent a Element + Bytes = 32 // number of bytes needed to represent a Element +) -// Bits number bits needed to represent Element -const Bits = 254 +// Field modulus q +const ( + q0 uint64 = 4332616871279656263 + q1 uint64 = 10917124144477883021 + q2 uint64 = 13281191951274694749 + q3 uint64 = 3486998266802970665 +) -// Bytes number bytes needed to represent Element -const Bytes = Limbs * 8 +var qElement = Element{ + q0, + q1, + q2, + q3, +} -// field modulus stored as big.Int -var _modulus big.Int +var _modulus big.Int // q stored as big.Int // Modulus returns q as a big.Int -// q = // -// 21888242871839275222246405745257275088696311157297823662689037894645226208583 +// q[base10] = 21888242871839275222246405745257275088696311157297823662689037894645226208583 +// q[base16] = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 func Modulus() *big.Int { return new(big.Int).Set(&_modulus) } -// q (modulus) -const qElementWord0 uint64 = 4332616871279656263 -const qElementWord1 uint64 = 10917124144477883021 -const qElementWord2 uint64 = 13281191951274694749 -const qElementWord3 uint64 = 3486998266802970665 - -var qElement = Element{ - qElementWord0, - qElementWord1, - qElementWord2, - qElementWord3, -} - -// Used for Montgomery reduction. (qInvNeg) q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r -const qInvNegLsw uint64 = 9786893198990664585 - -// rSquare -var rSquare = Element{ - 17522657719365597833, - 13107472804851548667, - 5164255478447964150, - 493319470278259999, -} - -var bigIntPool = sync.Pool{ - New: func() interface{} { - return new(big.Int) - }, -} +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 9786893198990664585 func init() { - _modulus.SetString("21888242871839275222246405745257275088696311157297823662689037894645226208583", 10) + _modulus.SetString("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47", 16) } // NewElement returns a new Element from a uint64 value // // it is equivalent to -// var v NewElement -// v.SetUint64(...) +// +// var v Element +// v.SetUint64(...) func NewElement(v uint64) Element { z := Element{v} z.Mul(&z, &rSquare) @@ -111,7 +101,7 @@ func NewElement(v uint64) Element { func (z *Element) SetUint64(v uint64) *Element { // sets z LSB to v (non-Montgomery form) and convert z to Montgomery form *z = Element{v} - return z.Mul(z, &rSquare) // z.ToMont() + return z.Mul(z, &rSquare) // z.toMont() } // SetInt64 sets z to v and returns z @@ -129,7 +119,7 @@ func (z *Element) SetInt64(v int64) *Element { return z } -// Set z = x +// Set z = x and returns z func (z *Element) Set(x *Element) *Element { z[0] = x[0] z[1] = x[1] @@ -140,13 +130,28 @@ func (z *Element) Set(x *Element) *Element { // SetInterface converts provided interface into Element // returns an error if provided type is not supported -// supported types: Element, *Element, uint64, int, string (interpreted as base10 integer), -// *big.Int, big.Int, []byte +// supported types: +// +// Element +// *Element +// uint64 +// int +// string (see SetString for valid formats) +// *big.Int +// big.Int +// []byte func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + if i1 == nil { + return nil, errors.New("can't set fp.Element with ") + } + switch c1 := i1.(type) { case Element: return z.Set(&c1), nil case *Element: + if c1 == nil { + return nil, errors.New("can't set fp.Element with ") + } return z.Set(c1), nil case uint8: return z.SetUint64(uint64(c1)), nil @@ -169,8 +174,11 @@ func (z *Element) SetInterface(i1 interface{}) (*Element, error) { case int: return z.SetInt64(int64(c1)), nil case string: - return z.SetString(c1), nil + return z.SetString(c1) case *big.Int: + if c1 == nil { + return nil, errors.New("can't set fp.Element with ") + } return z.SetBigInt(c1), nil case big.Int: return z.SetBigInt(&c1), nil @@ -199,7 +207,7 @@ func (z *Element) SetOne() *Element { return z } -// Div z = x*y^-1 mod q +// Div z = x*y⁻¹ (mod q) func (z *Element) Div(x, y *Element) *Element { var yInv Element yInv.Inverse(y) @@ -207,19 +215,14 @@ func (z *Element) Div(x, y *Element) *Element { return z } -// Bit returns the i'th bit, with lsb == bit 0. -// It is the responsability of the caller to convert from Montgomery to Regular form if needed -func (z *Element) Bit(i uint64) uint64 { - j := i / 64 - if j >= 4 { - return 0 - } - return uint64(z[j] >> (i % 64) & 1) +// Equal returns z == x; constant-time +func (z *Element) Equal(x *Element) bool { + return z.NotEqual(x) == 0 } -// Equal returns z == x -func (z *Element) Equal(x *Element) bool { - return (z[3] == x[3]) && (z[2] == x[2]) && (z[1] == x[1]) && (z[0] == x[0]) +// NotEqual returns 0 if and only if z == x; constant-time +func (z *Element) NotEqual(x *Element) uint64 { + return (z[3] ^ x[3]) | (z[2] ^ x[2]) | (z[1] ^ x[1]) | (z[0] ^ x[0]) } // IsZero returns z == 0 @@ -227,22 +230,38 @@ func (z *Element) IsZero() bool { return (z[3] | z[2] | z[1] | z[0]) == 0 } +// IsOne returns z == 1 +func (z *Element) IsOne() bool { + return ((z[3] ^ 1011752739694698287) | (z[2] ^ 7381016538464732716) | (z[1] ^ 754611498739239741) | (z[0] ^ 15230403791020821917)) == 0 +} + // IsUint64 reports whether z can be represented as an uint64. func (z *Element) IsUint64() bool { + zz := *z + zz.fromMont() + return zz.FitsOnOneWord() +} + +// Uint64 returns the uint64 representation of x. If x cannot be represented in a uint64, the result is undefined. +func (z *Element) Uint64() uint64 { + return z.Bits()[0] +} + +// FitsOnOneWord reports whether z words (except the least significant word) are 0 +// +// It is the responsibility of the caller to convert from Montgomery to Regular form if needed. +func (z *Element) FitsOnOneWord() bool { return (z[3] | z[2] | z[1]) == 0 } // Cmp compares (lexicographic order) z and x and returns: // -// -1 if z < x -// 0 if z == x -// +1 if z > x -// +// -1 if z < x +// 0 if z == x +// +1 if z > x func (z *Element) Cmp(x *Element) int { - _z := *z - _x := *x - _z.FromMont() - _x.FromMont() + _z := z.Bits() + _x := x.Bits() if _z[3] > _x[3] { return 1 } else if _z[3] < _x[3] { @@ -273,8 +292,7 @@ func (z *Element) LexicographicallyLargest() bool { // we check if the element is larger than (q-1) / 2 // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 - _z := *z - _z.FromMont() + _z := z.Bits() var b uint64 _, b = bits.Sub64(_z[0], 11389680472494603940, 0) @@ -285,53 +303,79 @@ func (z *Element) LexicographicallyLargest() bool { return b == 0 } -// SetRandom sets z to a random element < q +// SetRandom sets z to a uniform random value in [0, q). +// +// This might error only if reading from crypto/rand.Reader errors, +// in which case, value of z is undefined. func (z *Element) SetRandom() (*Element, error) { - var bytes [32]byte - if _, err := io.ReadFull(rand.Reader, bytes[:]); err != nil { - return nil, err + // this code is generated for all modulus + // and derived from go/src/crypto/rand/util.go + + // l is number of limbs * 8; the number of bytes needed to reconstruct 4 uint64 + const l = 32 + + // bitLen is the maximum bit length needed to encode a value < q. + const bitLen = 254 + + // k is the maximum byte length needed to encode a value < q. + const k = (bitLen + 7) / 8 + + // b is the number of bits in the most significant byte of q-1. + b := uint(bitLen % 8) + if b == 0 { + b = 8 } - z[0] = binary.BigEndian.Uint64(bytes[0:8]) - z[1] = binary.BigEndian.Uint64(bytes[8:16]) - z[2] = binary.BigEndian.Uint64(bytes[16:24]) - z[3] = binary.BigEndian.Uint64(bytes[24:32]) - z[3] %= 3486998266802970665 - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + var bytes [l]byte + + for { + // note that bytes[k:l] is always 0 + if _, err := io.ReadFull(rand.Reader, bytes[:k]); err != nil { + return nil, err + } + + // Clear unused bits in in the most significant byte to increase probability + // that the candidate is < q. + bytes[k-1] &= uint8(int(1<> 1 - z[0] = z[0]>>1 | z[1]<<63 z[1] = z[1]>>1 | z[2]<<63 z[2] = z[2]>>1 | z[3]<<63 @@ -339,323 +383,305 @@ func (z *Element) Halve() { } -// API with assembly impl - -// Mul z = x * y mod q -// see https://hackmd.io/@gnark/modular_multiplication -func (z *Element) Mul(x, y *Element) *Element { - mul(z, x, y) - return z -} - -// Square z = x * x mod q -// see https://hackmd.io/@gnark/modular_multiplication -func (z *Element) Square(x *Element) *Element { - mul(z, x, x) - return z -} - -// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// fromMont converts z in place (i.e. mutates) from Montgomery to regular representation // sets and returns z = z * 1 -func (z *Element) FromMont() *Element { +func (z *Element) fromMont() *Element { fromMont(z) return z } -// Add z = x + y mod q +// Add z = x + y (mod q) func (z *Element) Add(x, y *Element) *Element { - add(z, x, y) + + var carry uint64 + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], _ = bits.Add64(x[3], y[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } return z } -// Double z = x + x mod q, aka Lsh 1 +// Double z = x + x (mod q), aka Lsh 1 func (z *Element) Double(x *Element) *Element { - double(z, x) + + var carry uint64 + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], _ = bits.Add64(x[3], x[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } return z } -// Sub z = x - y mod q +// Sub z = x - y (mod q) func (z *Element) Sub(x, y *Element) *Element { - sub(z, x, y) + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], q0, 0) + z[1], c = bits.Add64(z[1], q1, c) + z[2], c = bits.Add64(z[2], q2, c) + z[3], _ = bits.Add64(z[3], q3, c) + } return z } // Neg z = q - x func (z *Element) Neg(x *Element) *Element { - neg(z, x) + if x.IsZero() { + z.SetZero() + return z + } + var borrow uint64 + z[0], borrow = bits.Sub64(q0, x[0], 0) + z[1], borrow = bits.Sub64(q1, x[1], borrow) + z[2], borrow = bits.Sub64(q2, x[2], borrow) + z[3], _ = bits.Sub64(q3, x[3], borrow) return z } -// Generic (no ADX instructions, no AMD64) versions of multiplication and squaring algorithms +// Select is a constant-time conditional move. +// If c=0, z = x0. Else z = x1 +func (z *Element) Select(c int, x0 *Element, x1 *Element) *Element { + cC := uint64((int64(c) | -int64(c)) >> 63) // "canonicized" into: 0 if c=0, -1 otherwise + z[0] = x0[0] ^ cC&(x0[0]^x1[0]) + z[1] = x0[1] ^ cC&(x0[1]^x1[1]) + z[2] = x0[2] ^ cC&(x0[2]^x1[2]) + z[3] = x0[3] ^ cC&(x0[3]^x1[3]) + return z +} +// _mulGeneric is unoptimized textbook CIOS +// it is a fallback solution on x86 when ADX instruction set is not available +// and is used for testing purposes. func _mulGeneric(z, x, y *Element) { - var t [4]uint64 - var c [3]uint64 - { - // round 0 - v := x[0] - c[1], c[0] = bits.Mul64(v, y[0]) - m := c[0] * 9786893198990664585 - c[2] = madd0(m, 4332616871279656263, c[0]) - c[1], c[0] = madd1(v, y[1], c[1]) - c[2], t[0] = madd2(m, 10917124144477883021, c[2], c[0]) - c[1], c[0] = madd1(v, y[2], c[1]) - c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd1(v, y[3], c[1]) - t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - { - // round 1 - v := x[1] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9786893198990664585 - c[2] = madd0(m, 4332616871279656263, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 10917124144477883021, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - { - // round 2 - v := x[2] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9786893198990664585 - c[2] = madd0(m, 4332616871279656263, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 10917124144477883021, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - { - // round 3 - v := x[3] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 9786893198990664585 - c[2] = madd0(m, 4332616871279656263, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], z[0] = madd2(m, 10917124144477883021, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], z[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - z[3], z[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + + var t [5]uint64 + var D uint64 + var m, C uint64 + // ----------------------------------- + // First loop + + C, t[0] = bits.Mul64(y[0], x[0]) + C, t[1] = madd1(y[0], x[1], C) + C, t[2] = madd1(y[0], x[2], C) + C, t[3] = madd1(y[0], x[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[1], x[0], t[0]) + C, t[1] = madd2(y[1], x[1], t[1], C) + C, t[2] = madd2(y[1], x[2], t[2], C) + C, t[3] = madd2(y[1], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[2], x[0], t[0]) + C, t[1] = madd2(y[2], x[1], t[1], C) + C, t[2] = madd2(y[2], x[2], t[2], C) + C, t[3] = madd2(y[2], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[3], x[0], t[0]) + C, t[1] = madd2(y[3], x[1], t[1], C) + C, t[2] = madd2(y[3], x[2], t[2], C) + C, t[3] = madd2(y[3], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + + if t[4] != 0 { + // we need to reduce, we have a result on 5 words var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(t[0], q0, 0) + z[1], b = bits.Sub64(t[1], q1, b) + z[2], b = bits.Sub64(t[2], q2, b) + z[3], _ = bits.Sub64(t[3], q3, b) + return } -} -func _mulWGeneric(z, x *Element, y uint64) { + // copy t into z + z[0] = t[0] + z[1] = t[1] + z[2] = t[2] + z[3] = t[3] - var t [4]uint64 - { - // round 0 - c1, c0 := bits.Mul64(y, x[0]) - m := c0 * 9786893198990664585 - c2 := madd0(m, 4332616871279656263, c0) - c1, c0 = madd1(y, x[1], c1) - c2, t[0] = madd2(m, 10917124144477883021, c2, c0) - c1, c0 = madd1(y, x[2], c1) - c2, t[1] = madd2(m, 13281191951274694749, c2, c0) - c1, c0 = madd1(y, x[3], c1) - t[3], t[2] = madd3(m, 3486998266802970665, c0, c2, c1) - } - { - // round 1 - m := t[0] * 9786893198990664585 - c2 := madd0(m, 4332616871279656263, t[0]) - c2, t[0] = madd2(m, 10917124144477883021, c2, t[1]) - c2, t[1] = madd2(m, 13281191951274694749, c2, t[2]) - t[3], t[2] = madd2(m, 3486998266802970665, t[3], c2) - } - { - // round 2 - m := t[0] * 9786893198990664585 - c2 := madd0(m, 4332616871279656263, t[0]) - c2, t[0] = madd2(m, 10917124144477883021, c2, t[1]) - c2, t[1] = madd2(m, 13281191951274694749, c2, t[2]) - t[3], t[2] = madd2(m, 3486998266802970665, t[3], c2) - } - { - // round 3 - m := t[0] * 9786893198990664585 - c2 := madd0(m, 4332616871279656263, t[0]) - c2, z[0] = madd2(m, 10917124144477883021, c2, t[1]) - c2, z[1] = madd2(m, 13281191951274694749, c2, t[2]) - z[3], z[2] = madd2(m, 3486998266802970665, t[3], c2) - } - - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } } func _fromMontGeneric(z *Element) { // the following lines implement z = z * 1 // with a modified CIOS montgomery multiplication + // see Mul for algorithm documentation { // m = z[0]n'[0] mod W - m := z[0] * 9786893198990664585 - C := madd0(m, 4332616871279656263, z[0]) - C, z[0] = madd2(m, 10917124144477883021, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } { // m = z[0]n'[0] mod W - m := z[0] * 9786893198990664585 - C := madd0(m, 4332616871279656263, z[0]) - C, z[0] = madd2(m, 10917124144477883021, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } { // m = z[0]n'[0] mod W - m := z[0] * 9786893198990664585 - C := madd0(m, 4332616871279656263, z[0]) - C, z[0] = madd2(m, 10917124144477883021, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } { // m = z[0]n'[0] mod W - m := z[0] * 9786893198990664585 - C := madd0(m, 4332616871279656263, z[0]) - C, z[0] = madd2(m, 10917124144477883021, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) - } -} - -func _addGeneric(z, x, y *Element) { - var carry uint64 - - z[0], carry = bits.Add64(x[0], y[0], 0) - z[1], carry = bits.Add64(x[1], y[1], carry) - z[2], carry = bits.Add64(x[2], y[2], carry) - z[3], _ = bits.Add64(x[3], y[3], carry) - - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) - } -} - -func _doubleGeneric(z, x *Element) { - var carry uint64 - - z[0], carry = bits.Add64(x[0], x[0], 0) - z[1], carry = bits.Add64(x[1], x[1], carry) - z[2], carry = bits.Add64(x[2], x[2], carry) - z[3], _ = bits.Add64(x[3], x[3], carry) - - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } } -func _subGeneric(z, x, y *Element) { - var b uint64 - z[0], b = bits.Sub64(x[0], y[0], 0) - z[1], b = bits.Sub64(x[1], y[1], b) - z[2], b = bits.Sub64(x[2], y[2], b) - z[3], b = bits.Sub64(x[3], y[3], b) - if b != 0 { - var c uint64 - z[0], c = bits.Add64(z[0], 4332616871279656263, 0) - z[1], c = bits.Add64(z[1], 10917124144477883021, c) - z[2], c = bits.Add64(z[2], 13281191951274694749, c) - z[3], _ = bits.Add64(z[3], 3486998266802970665, c) - } -} - -func _negGeneric(z, x *Element) { - if x.IsZero() { - z.SetZero() - return - } - var borrow uint64 - z[0], borrow = bits.Sub64(4332616871279656263, x[0], 0) - z[1], borrow = bits.Sub64(10917124144477883021, x[1], borrow) - z[2], borrow = bits.Sub64(13281191951274694749, x[2], borrow) - z[3], _ = bits.Sub64(3486998266802970665, x[3], borrow) -} - func _reduceGeneric(z *Element) { - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) - } -} - -func mulByConstant(z *Element, c uint8) { - switch c { - case 0: - z.SetZero() - return - case 1: - return - case 2: - z.Double(z) - return - case 3: - _z := *z - z.Double(z).Add(z, &_z) - case 5: - _z := *z - z.Double(z).Double(z).Add(z, &_z) - default: - var y Element - y.SetUint64(uint64(c)) - z.Mul(z, &y) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } } @@ -667,12 +693,12 @@ func BatchInvert(a []Element) []Element { return res } - zeroes := make([]bool, len(a)) + zeroes := bitset.New(uint(len(a))) accumulator := One() for i := 0; i < len(a); i++ { if a[i].IsZero() { - zeroes[i] = true + zeroes.Set(uint(i)) continue } res[i] = accumulator @@ -682,7 +708,7 @@ func BatchInvert(a []Element) []Element { accumulator.Inverse(&accumulator) for i := len(a) - 1; i >= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -713,18 +739,59 @@ func (z *Element) BitLen() int { return bits.Len64(z[0]) } -// Exp z = x^exponent mod q -func (z *Element) Exp(x Element, exponent *big.Int) *Element { - var bZero big.Int - if exponent.Cmp(&bZero) == 0 { +// Hash msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func Hash(msg, dst []byte, count int) ([]Element, error) { + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + const Bytes = 1 + (Bits-1)/8 + const L = 16 + Bytes + + lenInBytes := count * L + pseudoRandomBytes, err := hash.ExpandMsgXmd(msg, dst, lenInBytes) + if err != nil { + return nil, err + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + res := make([]Element, count) + for i := 0; i < count; i++ { + vv.SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + res[i].SetBigInt(vv) + } + + // release object into pool + pool.BigInt.Put(vv) + + return res, nil +} + +// Exp z = xᵏ (mod q) +func (z *Element) Exp(x Element, k *big.Int) *Element { + if k.IsUint64() && k.Uint64() == 0 { return z.SetOne() } + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q) == (x⁻¹)ᵏ (mod q) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = pool.BigInt.Get() + defer pool.BigInt.Put(e) + e.Neg(k) + } + z.Set(&x) - for i := exponent.BitLen() - 2; i >= 0; i-- { + for i := e.BitLen() - 2; i >= 0; i-- { z.Square(z) - if exponent.Bit(i) == 1 { + if e.Bit(i) == 1 { z.Mul(z, &x) } } @@ -732,15 +799,20 @@ func (z *Element) Exp(x Element, exponent *big.Int) *Element { return z } -// ToMont converts z to Montgomery form -// sets and returns z = z * r² -func (z *Element) ToMont() *Element { - return z.Mul(z, &rSquare) +// rSquare where r is the Montgommery constant +// see section 2.3.2 of Tolga Acar's thesis +// https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf +var rSquare = Element{ + 17522657719365597833, + 13107472804851548667, + 5164255478447964150, + 493319470278259999, } -// ToRegular returns z in regular form (doesn't mutate z) -func (z Element) ToRegular() Element { - return *z.FromMont() +// toMont converts z to Montgomery form +// sets and returns z = z * r² +func (z *Element) toMont() *Element { + return z.Mul(z, &rSquare) } // String returns the decimal representation of z as generated by @@ -749,12 +821,23 @@ func (z *Element) String() string { return z.Text(10) } +// toBigInt returns z as a big.Int in Montgomery form +func (z *Element) toBigInt(res *big.Int) *big.Int { + var b [Bytes]byte + binary.BigEndian.PutUint64(b[24:32], z[0]) + binary.BigEndian.PutUint64(b[16:24], z[1]) + binary.BigEndian.PutUint64(b[8:16], z[2]) + binary.BigEndian.PutUint64(b[0:8], z[3]) + + return res.SetBytes(b[:]) +} + // Text returns the string representation of z in the given base. // Base must be between 2 and 36, inclusive. The result uses the // lower-case letters 'a' to 'z' for digit values 10 to 35. // No prefix (such as "0x") is added to the string. If z is a nil // pointer it returns "". -// If base == 10 and -z fits in a uint64 prefix "-" is added to the string. +// If base == 10 and -z fits in a uint16 prefix "-" is added to the string. func (z *Element) Text(base int) string { if base < 2 || base > 36 { panic("invalid base") @@ -762,77 +845,110 @@ func (z *Element) Text(base int) string { if z == nil { return "" } - zz := *z - zz.FromMont() - if zz.IsUint64() { - return strconv.FormatUint(zz[0], base) - } else if base == 10 { + + const maxUint16 = 65535 + if base == 10 { var zzNeg Element zzNeg.Neg(z) - zzNeg.FromMont() - if zzNeg.IsUint64() { + zzNeg.fromMont() + if zzNeg.FitsOnOneWord() && zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { return "-" + strconv.FormatUint(zzNeg[0], base) } } - vv := bigIntPool.Get().(*big.Int) - r := zz.ToBigInt(vv).Text(base) - bigIntPool.Put(vv) + zz := *z + zz.fromMont() + if zz.FitsOnOneWord() { + return strconv.FormatUint(zz[0], base) + } + vv := pool.BigInt.Get() + r := zz.toBigInt(vv).Text(base) + pool.BigInt.Put(vv) return r } -// ToBigInt returns z as a big.Int in Montgomery form -func (z *Element) ToBigInt(res *big.Int) *big.Int { - var b [Limbs * 8]byte - binary.BigEndian.PutUint64(b[24:32], z[0]) - binary.BigEndian.PutUint64(b[16:24], z[1]) - binary.BigEndian.PutUint64(b[8:16], z[2]) - binary.BigEndian.PutUint64(b[0:8], z[3]) - - return res.SetBytes(b[:]) +// BigInt sets and return z as a *big.Int +func (z *Element) BigInt(res *big.Int) *big.Int { + _z := *z + _z.fromMont() + return _z.toBigInt(res) } // ToBigIntRegular returns z as a big.Int in regular form +// +// Deprecated: use BigInt(*big.Int) instead func (z Element) ToBigIntRegular(res *big.Int) *big.Int { - z.FromMont() - return z.ToBigInt(res) + z.fromMont() + return z.toBigInt(res) } -// Bytes returns the regular (non montgomery) value -// of z as a big-endian byte array. -func (z *Element) Bytes() (res [Limbs * 8]byte) { - _z := z.ToRegular() - binary.BigEndian.PutUint64(res[24:32], _z[0]) - binary.BigEndian.PutUint64(res[16:24], _z[1]) - binary.BigEndian.PutUint64(res[8:16], _z[2]) - binary.BigEndian.PutUint64(res[0:8], _z[3]) +// Bits provides access to z by returning its value as a little-endian [4]uint64 array. +// Bits is intended to support implementation of missing low-level Element +// functionality outside this package; it should be avoided otherwise. +func (z *Element) Bits() [4]uint64 { + _z := *z + fromMont(&_z) + return _z +} +// Bytes returns the value of z as a big-endian byte array +func (z *Element) Bytes() (res [Bytes]byte) { + BigEndian.PutElement(&res, *z) return } -// Marshal returns the regular (non montgomery) value -// of z as a big-endian byte slice. +// Marshal returns the value of z as a big-endian byte slice func (z *Element) Marshal() []byte { b := z.Bytes() return b[:] } +// Unmarshal is an alias for SetBytes, it sets z to the value of e. +func (z *Element) Unmarshal(e []byte) { + z.SetBytes(e) +} + // SetBytes interprets e as the bytes of a big-endian unsigned integer, -// sets z to that value (in Montgomery form), and returns z. +// sets z to that value, and returns z. func (z *Element) SetBytes(e []byte) *Element { + if len(e) == Bytes { + // fast path + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err == nil { + *z = v + return z + } + } + + // slow path. // get a big int from our pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() vv.SetBytes(e) // set big int z.SetBigInt(vv) // put temporary object back in pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) return z } -// SetBigInt sets z to v (regular form) and returns z in Montgomery form +// SetBytesCanonical interprets e as the bytes of a big-endian 32-byte integer. +// If e is not a 32-byte slice or encodes a value higher than q, +// SetBytesCanonical returns an error. +func (z *Element) SetBytesCanonical(e []byte) error { + if len(e) != Bytes { + return errors.New("invalid fp.Element encoding") + } + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err != nil { + return err + } + *z = v + return nil +} + +// SetBigInt sets z to v and returns z func (z *Element) SetBigInt(v *big.Int) *Element { z.SetZero() @@ -849,17 +965,16 @@ func (z *Element) SetBigInt(v *big.Int) *Element { } // get temporary big int from the pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() // copy input + modular reduction - vv.Set(v) vv.Mod(v, &_modulus) // set big int byte value z.setBigInt(vv) // release object into pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) return z } @@ -881,39 +996,40 @@ func (z *Element) setBigInt(v *big.Int) *Element { } } - return z.ToMont() + return z.toMont() } // SetString creates a big.Int with number and calls SetBigInt on z // // The number prefix determines the actual base: A prefix of -// ''0b'' or ''0B'' selects base 2, ''0'', ''0o'' or ''0O'' selects base 8, -// and ''0x'' or ''0X'' selects base 16. Otherwise, the selected base is 10 +// ”0b” or ”0B” selects base 2, ”0”, ”0o” or ”0O” selects base 8, +// and ”0x” or ”0X” selects base 16. Otherwise, the selected base is 10 // and no prefix is accepted. // // For base 16, lower and upper case letters are considered the same: // The letters 'a' to 'f' and 'A' to 'F' represent digit values 10 to 15. // -// An underscore character ''_'' may appear between a base +// An underscore character ”_” may appear between a base // prefix and an adjacent digit, and between successive digits; such // underscores do not change the value of the number. // Incorrect placement of underscores is reported as a panic if there // are no other errors. // -func (z *Element) SetString(number string) *Element { +// If the number is invalid this method leaves z unchanged and returns nil, error. +func (z *Element) SetString(number string) (*Element, error) { // get temporary big int from the pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() if _, ok := vv.SetString(number, 0); !ok { - panic("Element.SetString failed -> can't parse number into a big.Int " + number) + return nil, errors.New("Element.SetString failed -> can't parse number into a big.Int " + number) } z.SetBigInt(vv) // release object into pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) - return z + return z, nil } // MarshalJSON returns json encoding of z (z.Text(10)) @@ -951,7 +1067,7 @@ func (z *Element) UnmarshalJSON(data []byte) error { } // get temporary big int from the pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() if _, ok := vv.SetString(s, 0); !ok { return errors.New("can't parse into a big.Int: " + s) @@ -960,10 +1076,79 @@ func (z *Element) UnmarshalJSON(data []byte) error { z.SetBigInt(vv) // release object into pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) return nil } +// A ByteOrder specifies how to convert byte slices into a Element +type ByteOrder interface { + Element(*[Bytes]byte) (Element, error) + PutElement(*[Bytes]byte, Element) + String() string +} + +// BigEndian is the big-endian implementation of ByteOrder and AppendByteOrder. +var BigEndian bigEndian + +type bigEndian struct{} + +// Element interpret b is a big-endian 32-byte slice. +// If b encodes a value higher than q, Element returns error. +func (bigEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.BigEndian.Uint64((*b)[24:32]) + z[1] = binary.BigEndian.Uint64((*b)[16:24]) + z[2] = binary.BigEndian.Uint64((*b)[8:16]) + z[3] = binary.BigEndian.Uint64((*b)[0:8]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fp.Element encoding") + } + + z.toMont() + return z, nil +} + +func (bigEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.BigEndian.PutUint64((*b)[24:32], e[0]) + binary.BigEndian.PutUint64((*b)[16:24], e[1]) + binary.BigEndian.PutUint64((*b)[8:16], e[2]) + binary.BigEndian.PutUint64((*b)[0:8], e[3]) +} + +func (bigEndian) String() string { return "BigEndian" } + +// LittleEndian is the little-endian implementation of ByteOrder and AppendByteOrder. +var LittleEndian littleEndian + +type littleEndian struct{} + +func (littleEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.LittleEndian.Uint64((*b)[0:8]) + z[1] = binary.LittleEndian.Uint64((*b)[8:16]) + z[2] = binary.LittleEndian.Uint64((*b)[16:24]) + z[3] = binary.LittleEndian.Uint64((*b)[24:32]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fp.Element encoding") + } + + z.toMont() + return z, nil +} + +func (littleEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.LittleEndian.PutUint64((*b)[0:8], e[0]) + binary.LittleEndian.PutUint64((*b)[8:16], e[1]) + binary.LittleEndian.PutUint64((*b)[16:24], e[2]) + binary.LittleEndian.PutUint64((*b)[24:32], e[3]) +} + +func (littleEndian) String() string { return "LittleEndian" } + // Legendre returns the Legendre symbol of z (either +1, -1, or 0.) func (z *Element) Legendre() int { var l Element @@ -975,13 +1160,13 @@ func (z *Element) Legendre() int { } // if l == 1 - if (l[3] == 1011752739694698287) && (l[2] == 7381016538464732716) && (l[1] == 754611498739239741) && (l[0] == 15230403791020821917) { + if l.IsOne() { return 1 } return -1 } -// Sqrt z = √x mod q +// Sqrt z = √x (mod q) // if the square root doesn't exist (x is not a square mod q) // Sqrt leaves z unchanged and returns nil func (z *Element) Sqrt(x *Element) *Element { @@ -997,64 +1182,40 @@ func (z *Element) Sqrt(x *Element) *Element { return nil } -func max(a int, b int) int { - if a > b { - return a - } - return b -} - -func min(a int, b int) int { - if a < b { - return a - } - return b -} - -const updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) -const updateFactorIdentityMatrixRow0 = 1 -const updateFactorIdentityMatrixRow1 = 1 << 32 - -func updateFactorsDecompose(c int64) (int64, int64) { - c += updateFactorsConversionBias - const low32BitsFilter int64 = 0xFFFFFFFF - f := c&low32BitsFilter - 0x7FFFFFFF - g := c>>32&low32BitsFilter - 0x7FFFFFFF - return f, g -} - -const k = 32 // word size / 2 -const signBitSelector = uint64(1) << 63 -const approxLowBitsN = k - 1 -const approxHighBitsN = k + 1 -const inversionCorrectionFactorWord0 = 11111708840330028223 -const inversionCorrectionFactorWord1 = 3098618286181893933 -const inversionCorrectionFactorWord2 = 756602578711705709 -const inversionCorrectionFactorWord3 = 1041752015607019851 +const ( + k = 32 // word size / 2 + signBitSelector = uint64(1) << 63 + approxLowBitsN = k - 1 + approxHighBitsN = k + 1 +) -const invIterationsN = 18 +const ( + inversionCorrectionFactorWord0 = 11111708840330028223 + inversionCorrectionFactorWord1 = 3098618286181893933 + inversionCorrectionFactorWord2 = 756602578711705709 + inversionCorrectionFactorWord3 = 1041752015607019851 + invIterationsN = 18 +) -// Inverse z = x⁻¹ mod q -// Implements "Optimized Binary GCD for Modular Inversion" -// https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf +// Inverse z = x⁻¹ (mod q) +// +// if x == 0, sets and returns z = x func (z *Element) Inverse(x *Element) *Element { - if x.IsZero() { - z.SetZero() - return z - } + // Implements "Optimized Binary GCD for Modular Inversion" + // https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf a := *x b := Element{ - qElementWord0, - qElementWord1, - qElementWord2, - qElementWord3, + q0, + q1, + q2, + q3, } // b := q u := Element{1} - // Update factors: we get [u; v]:= [f0 g0; f1 g1] [u; v] - // c_i = f_i + 2³¹ - 1 + 2³² * (g_i + 2³¹ - 1) + // Update factors: we get [u; v] ← [f₀ g₀; f₁ g₁] [u; v] + // cᵢ = fᵢ + 2³¹ - 1 + 2³² * (gᵢ + 2³¹ - 1) var c0, c1 int64 // Saved update factors to reduce the number of field multiplications @@ -1071,12 +1232,14 @@ func (z *Element) Inverse(x *Element) *Element { n := max(a.BitLen(), b.BitLen()) aApprox, bApprox := approximate(&a, n), approximate(&b, n) - // After 0 iterations, we have f₀ ≤ 2⁰ and f₁ < 2⁰ - // f0, g0, f1, g1 = 1, 0, 0, 1 + // f₀, g₀, f₁, g₁ = 1, 0, 0, 1 c0, c1 = updateFactorIdentityMatrixRow0, updateFactorIdentityMatrixRow1 for j := 0; j < approxLowBitsN; j++ { + // -2ʲ < f₀, f₁ ≤ 2ʲ + // |f₀| + |f₁| < 2ʲ⁺¹ + if aApprox&1 == 0 { aApprox /= 2 } else { @@ -1085,17 +1248,20 @@ func (z *Element) Inverse(x *Element) *Element { s = bApprox - aApprox bApprox = aApprox c0, c1 = c1, c0 + // invariants unchanged } aApprox = s / 2 c0 = c0 - c1 - // Now |f₀| < 2ʲ + 2ʲ = 2ʲ⁺¹ - // |f₁| ≤ 2ʲ still + // Now |f₀| < 2ʲ⁺¹ ≤ 2ʲ⁺¹ (only the weaker inequality is needed, strictly speaking) + // Started with f₀ > -2ʲ and f₁ ≤ 2ʲ, so f₀ - f₁ > -2ʲ⁺¹ + // Invariants unchanged for f₁ } c1 *= 2 - // |f₁| ≤ 2ʲ⁺¹ + // -2ʲ⁺¹ < f₁ ≤ 2ʲ⁺¹ + // So now |f₀| + |f₁| < 2ʲ⁺² } s = a @@ -1107,7 +1273,7 @@ func (z *Element) Inverse(x *Element) *Element { if aHi&signBitSelector != 0 { // if aHi < 0 c0, g0 = -c0, -g0 - aHi = a.neg(&a, aHi) + aHi = negL(&a, aHi) } // right-shift a by k-1 bits a[0] = (a[0] >> approxLowBitsN) | ((a[1]) << approxHighBitsN) @@ -1122,7 +1288,7 @@ func (z *Element) Inverse(x *Element) *Element { if bHi&signBitSelector != 0 { // if bHi < 0 f1, c1 = -f1, -c1 - bHi = b.neg(&b, bHi) + bHi = negL(&b, bHi) } // right-shift b by k-1 bits b[0] = (b[0] >> approxLowBitsN) | ((b[1]) << approxHighBitsN) @@ -1132,20 +1298,24 @@ func (z *Element) Inverse(x *Element) *Element { if i&1 == 1 { // Combine current update factors with previously stored ones - // [f₀, g₀; f₁, g₁] ← [f₀, g₀; f₁, g₀] [pf₀, pg₀; pf₀, pg₀] - // We have |f₀|, |g₀|, |pf₀|, |pf₁| ≤ 2ᵏ⁻¹, and that |pf_i| < 2ᵏ⁻¹ for i ∈ {0, 1} - // Then for the new value we get |f₀| < 2ᵏ⁻¹ × 2ᵏ⁻¹ + 2ᵏ⁻¹ × 2ᵏ⁻¹ = 2²ᵏ⁻¹ - // Which leaves us with an extra bit for the sign + // [F₀, G₀; F₁, G₁] ← [f₀, g₀; f₁, g₁] [pf₀, pg₀; pf₁, pg₁], with capital letters denoting new combined values + // We get |F₀| = | f₀pf₀ + g₀pf₁ | ≤ |f₀pf₀| + |g₀pf₁| = |f₀| |pf₀| + |g₀| |pf₁| ≤ 2ᵏ⁻¹|pf₀| + 2ᵏ⁻¹|pf₁| + // = 2ᵏ⁻¹ (|pf₀| + |pf₁|) < 2ᵏ⁻¹ 2ᵏ = 2²ᵏ⁻¹ + // So |F₀| < 2²ᵏ⁻¹ meaning it fits in a 2k-bit signed register - // c0 aliases f0, c1 aliases g1 + // c₀ aliases f₀, c₁ aliases g₁ c0, g0, f1, c1 = c0*pf0+g0*pf1, c0*pg0+g0*pg1, f1*pf0+c1*pf1, f1*pg0+c1*pg1 s = u - u.linearCombSosSigned(&u, c0, &v, g0) - v.linearCombSosSigned(&s, f1, &v, c1) + + // 0 ≤ u, v < 2²⁵⁵ + // |F₀|, |G₀| < 2⁶³ + u.linearComb(&u, c0, &v, g0) + // |F₁|, |G₁| < 2⁶³ + v.linearComb(&s, f1, &v, c1) } else { // Save update factors @@ -1153,19 +1323,51 @@ func (z *Element) Inverse(x *Element) *Element { } } - // For every iteration that we miss, v is not being multiplied by 2²ᵏ⁻² - const pSq int64 = 1 << (2 * (k - 1)) - // If the function is constant-time ish, this loop will not run (probably no need to take it out explicitly) + // For every iteration that we miss, v is not being multiplied by 2ᵏ⁻² + const pSq uint64 = 1 << (2 * (k - 1)) + a = Element{pSq} + // If the function is constant-time ish, this loop will not run (no need to take it out explicitly) for ; i < invIterationsN; i += 2 { - v.mulWSigned(&v, pSq) + // could optimize further with mul by word routine or by pre-computing a table since with k=26, + // we would multiply by pSq up to 13times; + // on x86, the assembly routine outperforms generic code for mul by word + // on arm64, we may loose up to ~5% for 6 limbs + v.Mul(&v, &a) } + u.Set(x) // for correctness check + z.Mul(&v, &Element{ inversionCorrectionFactorWord0, inversionCorrectionFactorWord1, inversionCorrectionFactorWord2, inversionCorrectionFactorWord3, }) + + // correctness check + v.Mul(&u, z) + if !v.IsOne() && !u.IsZero() { + return z.inverseExp(u) + } + + return z +} + +// inverseExp computes z = x⁻¹ (mod q) = x**(q-2) (mod q) +func (z *Element) inverseExp(x Element) *Element { + // e == q-2 + e := Modulus() + e.Sub(e, big.NewInt(2)) + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + return z } @@ -1194,80 +1396,88 @@ func approximate(x *Element, nBits int) uint64 { return lo | mid | hi } -func (z *Element) linearCombSosSigned(x *Element, xC int64, y *Element, yC int64) { +// linearComb z = xC * x + yC * y; +// 0 ≤ x, y < 2²⁵⁴ +// |xC|, |yC| < 2⁶³ +func (z *Element) linearComb(x *Element, xC int64, y *Element, yC int64) { + // | (hi, z) | < 2 * 2⁶³ * 2²⁵⁴ = 2³¹⁸ + // therefore | hi | < 2⁶² ≤ 2⁶³ hi := z.linearCombNonModular(x, xC, y, yC) z.montReduceSigned(z, hi) } -// montReduceSigned SOS algorithm; xHi must be at most 63 bits long. Last bit of xHi may be used as a sign bit +// montReduceSigned z = (xHi * r + x) * r⁻¹ using the SOS algorithm +// Requires |xHi| < 2⁶³. Most significant bit of xHi is the sign bit. func (z *Element) montReduceSigned(x *Element, xHi uint64) { - const signBitRemover = ^signBitSelector - neg := xHi&signBitSelector != 0 + mustNeg := xHi&signBitSelector != 0 // the SOS implementation requires that most significant bit is 0 // Let X be xHi*r + x - // note that if X is negative we would have initially stored it as 2⁶⁴ r + X + // If X is negative we would have initially stored it as 2⁶⁴ r + X (à la 2's complement) xHi &= signBitRemover // with this a negative X is now represented as 2⁶³ r + X var t [2*Limbs - 1]uint64 var C uint64 - m := x[0] * qInvNegLsw + m := x[0] * qInvNeg - C = madd0(m, qElementWord0, x[0]) - C, t[1] = madd2(m, qElementWord1, x[1], C) - C, t[2] = madd2(m, qElementWord2, x[2], C) - C, t[3] = madd2(m, qElementWord3, x[3], C) + C = madd0(m, q0, x[0]) + C, t[1] = madd2(m, q1, x[1], C) + C, t[2] = madd2(m, q2, x[2], C) + C, t[3] = madd2(m, q3, x[3], C) - // the high word of m * qElement[3] is at most 62 bits - // x[3] + C is at most 65 bits (high word at most 1 bit) - // Thus the resulting C will be at most 63 bits + // m * qElement[3] ≤ (2⁶⁴ - 1) * (2⁶³ - 1) = 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + // x[3] + C ≤ 2*(2⁶⁴ - 1) = 2⁶⁵ - 2 + // On LHS, (C, t[3]) ≤ 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + 2⁶⁵ - 2 = 2¹²⁷ + 2⁶³ - 1 + // So on LHS, C ≤ 2⁶³ t[4] = xHi + C - // xHi and C are 63 bits, therefore no overflow + // xHi + C < 2⁶³ + 2⁶³ = 2⁶⁴ + // { const i = 1 - m = t[i] * qInvNegLsw + m = t[i] * qInvNeg - C = madd0(m, qElementWord0, t[i+0]) - C, t[i+1] = madd2(m, qElementWord1, t[i+1], C) - C, t[i+2] = madd2(m, qElementWord2, t[i+2], C) - C, t[i+3] = madd2(m, qElementWord3, t[i+3], C) + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) t[i+Limbs] += C } { const i = 2 - m = t[i] * qInvNegLsw + m = t[i] * qInvNeg - C = madd0(m, qElementWord0, t[i+0]) - C, t[i+1] = madd2(m, qElementWord1, t[i+1], C) - C, t[i+2] = madd2(m, qElementWord2, t[i+2], C) - C, t[i+3] = madd2(m, qElementWord3, t[i+3], C) + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) t[i+Limbs] += C } { const i = 3 - m := t[i] * qInvNegLsw + m := t[i] * qInvNeg - C = madd0(m, qElementWord0, t[i+0]) - C, z[0] = madd2(m, qElementWord1, t[i+1], C) - C, z[1] = madd2(m, qElementWord2, t[i+2], C) - z[3], z[2] = madd2(m, qElementWord3, t[i+3], C) + C = madd0(m, q0, t[i+0]) + C, z[0] = madd2(m, q1, t[i+1], C) + C, z[1] = madd2(m, q2, t[i+2], C) + z[3], z[2] = madd2(m, q3, t[i+3], C) } - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 10917124144477883021 || (z[1] == 10917124144477883021 && (z[0] < 4332616871279656263))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4332616871279656263, 0) - z[1], b = bits.Sub64(z[1], 10917124144477883021, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } - if neg { + // + + if mustNeg { // We have computed ( 2⁶³ r + X ) r⁻¹ = 2⁶³ + X r⁻¹ instead var b uint64 z[0], b = bits.Sub64(z[0], signBitSelector, 0) @@ -1276,45 +1486,51 @@ func (z *Element) montReduceSigned(x *Element, xHi uint64) { z[3], b = bits.Sub64(z[3], 0, b) // Occurs iff x == 0 && xHi < 0, i.e. X = rX' for -2⁶³ ≤ X' < 0 + if b != 0 { // z[3] = -1 // negative: add q const neg1 = 0xFFFFFFFFFFFFFFFF - b = 0 - z[0], b = bits.Add64(z[0], qElementWord0, b) - z[1], b = bits.Add64(z[1], qElementWord1, b) - z[2], b = bits.Add64(z[2], qElementWord2, b) - z[3], _ = bits.Add64(neg1, qElementWord3, b) + var carry uint64 + + z[0], carry = bits.Add64(z[0], q0, 0) + z[1], carry = bits.Add64(z[1], q1, carry) + z[2], carry = bits.Add64(z[2], q2, carry) + z[3], _ = bits.Add64(neg1, q3, carry) } } } -// mulWSigned mul word signed (w/ montgomery reduction) -func (z *Element) mulWSigned(x *Element, y int64) { - m := y >> 63 - _mulWGeneric(z, x, uint64((y^m)-m)) - // multiply by abs(y) - if y < 0 { - z.Neg(z) - } +const ( + updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) + updateFactorIdentityMatrixRow0 = 1 + updateFactorIdentityMatrixRow1 = 1 << 32 +) + +func updateFactorsDecompose(c int64) (int64, int64) { + c += updateFactorsConversionBias + const low32BitsFilter int64 = 0xFFFFFFFF + f := c&low32BitsFilter - 0x7FFFFFFF + g := c>>32&low32BitsFilter - 0x7FFFFFFF + return f, g } -func (z *Element) neg(x *Element, xHi uint64) uint64 { +// negL negates in place [x | xHi] and return the new most significant word xHi +func negL(x *Element, xHi uint64) uint64 { var b uint64 - z[0], b = bits.Sub64(0, x[0], 0) - z[1], b = bits.Sub64(0, x[1], b) - z[2], b = bits.Sub64(0, x[2], b) - z[3], b = bits.Sub64(0, x[3], b) + x[0], b = bits.Sub64(0, x[0], 0) + x[1], b = bits.Sub64(0, x[1], b) + x[2], b = bits.Sub64(0, x[2], b) + x[3], b = bits.Sub64(0, x[3], b) xHi, _ = bits.Sub64(0, xHi, b) return xHi } -// regular multiplication by one word regular (non montgomery) -// Fewer additions than the branch-free for positive y. Could be faster on some architectures -func (z *Element) mulWRegular(x *Element, y int64) uint64 { +// mulWNonModular multiplies by one word in non-montgomery, without reducing +func (z *Element) mulWNonModular(x *Element, y int64) uint64 { // w := abs(y) m := y >> 63 @@ -1327,83 +1543,21 @@ func (z *Element) mulWRegular(x *Element, y int64) uint64 { c, z[3] = madd1(x[3], w, c) if y < 0 { - c = z.neg(z, c) + c = negL(z, c) } return c } -/* -Removed: seems slower -// mulWRegular branch-free regular multiplication by one word (non montgomery) -func (z *Element) mulWRegularBf(x *Element, y int64) uint64 { - - w := uint64(y) - allNeg := uint64(y >> 63) // -1 if y < 0, 0 o.w - - // s[0], s[1] so results are not stored immediately in z. - // x[i] will be needed in the i+1 th iteration. We don't want to overwrite it in case x = z - var s [2]uint64 - var h [2]uint64 - - h[0], s[0] = bits.Mul64(x[0], w) - - c := uint64(0) - b := uint64(0) - - { - const curI = 1 % 2 - const prevI = 1 - curI - const iMinusOne = 1 - 1 - - h[curI], s[curI] = bits.Mul64(x[1], w) - s[curI], c = bits.Add64(s[curI], h[prevI], c) - s[curI], b = bits.Sub64(s[curI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - } - - { - const curI = 2 % 2 - const prevI = 1 - curI - const iMinusOne = 2 - 1 - - h[curI], s[curI] = bits.Mul64(x[2], w) - s[curI], c = bits.Add64(s[curI], h[prevI], c) - s[curI], b = bits.Sub64(s[curI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - } - - { - const curI = 3 % 2 - const prevI = 1 - curI - const iMinusOne = 3 - 1 - - h[curI], s[curI] = bits.Mul64(x[3], w) - s[curI], c = bits.Add64(s[curI], h[prevI], c) - s[curI], b = bits.Sub64(s[curI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - } - { - const curI = 4 % 2 - const prevI = 1 - curI - const iMinusOne = 3 - - s[curI], _ = bits.Sub64(h[prevI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - - return s[curI] + c - } -}*/ - -// Requires NoCarry +// linearCombNonModular computes a linear combination without modular reduction func (z *Element) linearCombNonModular(x *Element, xC int64, y *Element, yC int64) uint64 { var yTimes Element - yHi := yTimes.mulWRegular(y, yC) - xHi := z.mulWRegular(x, xC) + yHi := yTimes.mulWNonModular(y, yC) + xHi := z.mulWNonModular(x, xC) - carry := uint64(0) - z[0], carry = bits.Add64(z[0], yTimes[0], carry) + var carry uint64 + z[0], carry = bits.Add64(z[0], yTimes[0], 0) z[1], carry = bits.Add64(z[1], yTimes[1], carry) z[2], carry = bits.Add64(z[2], yTimes[2], carry) z[3], carry = bits.Add64(z[3], yTimes[3], carry) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_fuzz.go deleted file mode 100644 index d18bd4bb40c..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_fuzz.go +++ /dev/null @@ -1,136 +0,0 @@ -//go:build gofuzz -// +build gofuzz - -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fp - -import ( - "bytes" - "encoding/binary" - "io" - "math/big" - "math/bits" -) - -const ( - fuzzInteresting = 1 - fuzzNormal = 0 - fuzzDiscard = -1 -) - -// Fuzz arithmetic operations fuzzer -func Fuzz(data []byte) int { - r := bytes.NewReader(data) - - var e1, e2 Element - e1.SetRawBytes(r) - e2.SetRawBytes(r) - - { - // mul assembly - - var c, _c Element - a, _a, b, _b := e1, e1, e2, e2 - c.Mul(&a, &b) - _mulGeneric(&_c, &_a, &_b) - - if !c.Equal(&_c) { - panic("mul asm != mul generic on Element") - } - } - - { - // inverse - inv := e1 - inv.Inverse(&inv) - - var bInv, b1, b2 big.Int - e1.ToBigIntRegular(&b1) - bInv.ModInverse(&b1, Modulus()) - inv.ToBigIntRegular(&b2) - - if b2.Cmp(&bInv) != 0 { - panic("inverse operation doesn't match big int result") - } - } - - { - // a + -a == 0 - a, b := e1, e1 - b.Neg(&b) - a.Add(&a, &b) - if !a.IsZero() { - panic("a + -a != 0") - } - } - - return fuzzNormal - -} - -// SetRawBytes reads up to Bytes (bytes needed to represent Element) from reader -// and interpret it as big endian uint64 -// used for fuzzing purposes only -func (z *Element) SetRawBytes(r io.Reader) { - - buf := make([]byte, 8) - - for i := 0; i < len(z); i++ { - if _, err := io.ReadFull(r, buf); err != nil { - goto eof - } - z[i] = binary.BigEndian.Uint64(buf[:]) - } -eof: - z[3] %= qElement[3] - - if z.BiggerModulus() { - var b uint64 - z[0], b = bits.Sub64(z[0], qElement[0], 0) - z[1], b = bits.Sub64(z[1], qElement[1], b) - z[2], b = bits.Sub64(z[2], qElement[2], b) - z[3], b = bits.Sub64(z[3], qElement[3], b) - } - - return -} - -func (z *Element) BiggerModulus() bool { - if z[3] > qElement[3] { - return true - } - if z[3] < qElement[3] { - return false - } - - if z[2] > qElement[2] { - return true - } - if z[2] < qElement[2] { - return false - } - - if z[1] > qElement[1] { - return true - } - if z[1] < qElement[1] { - return false - } - - return z[0] >= qElement[0] -} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_mul_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_mul_amd64.s index 54af6c35873..e58b316819c 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_mul_amd64.s +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_mul_amd64.s @@ -1,4 +1,4 @@ -// +build !amd64_adx +// +build !purego // Copyright 2020 ConsenSys Software Inc. // @@ -45,8 +45,7 @@ GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 // mul(res, x, y *Element) TEXT ·mul(SB), $24-24 - // the algorithm is described here - // https://hackmd.io/@gnark/modular_multiplication + // the algorithm is described in the Element.Mul declaration (.go) // however, to benefit from the ADCX and ADOX carry chains // we split the inner loops in 2: // for i=0 to N-1 diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.go index 73a3711ec07..83bba45aedf 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.go @@ -1,3 +1,6 @@ +//go:build !purego +// +build !purego + // Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,18 +28,6 @@ func MulBy5(x *Element) //go:noescape func MulBy13(x *Element) -//go:noescape -func add(res, x, y *Element) - -//go:noescape -func sub(res, x, y *Element) - -//go:noescape -func neg(res, x *Element) - -//go:noescape -func double(res, x *Element) - //go:noescape func mul(res, x, y *Element) @@ -46,5 +37,71 @@ func fromMont(res *Element) //go:noescape func reduce(res *Element) +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +// //go:noescape func Butterfly(a, b *Element) + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + mul(z, x, y) + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for doc. + mul(z, x, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.s index 5b8b1f0e76b..48f34db8fe5 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.s +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_amd64.s @@ -1,3 +1,5 @@ +// +build !purego + // Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,118 +42,6 @@ GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 CMOVQCS rb2, ra2; \ CMOVQCS rb3, ra3; \ -// add(res, x, y *Element) -TEXT ·add(SB), NOSPLIT, $0-24 - MOVQ x+8(FP), AX - MOVQ 0(AX), CX - MOVQ 8(AX), BX - MOVQ 16(AX), SI - MOVQ 24(AX), DI - MOVQ y+16(FP), DX - ADDQ 0(DX), CX - ADCQ 8(DX), BX - ADCQ 16(DX), SI - ADCQ 24(DX), DI - - // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) - REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) - - MOVQ res+0(FP), R12 - MOVQ CX, 0(R12) - MOVQ BX, 8(R12) - MOVQ SI, 16(R12) - MOVQ DI, 24(R12) - RET - -// sub(res, x, y *Element) -TEXT ·sub(SB), NOSPLIT, $0-24 - XORQ DI, DI - MOVQ x+8(FP), SI - MOVQ 0(SI), AX - MOVQ 8(SI), DX - MOVQ 16(SI), CX - MOVQ 24(SI), BX - MOVQ y+16(FP), SI - SUBQ 0(SI), AX - SBBQ 8(SI), DX - SBBQ 16(SI), CX - SBBQ 24(SI), BX - MOVQ $0x3c208c16d87cfd47, R8 - MOVQ $0x97816a916871ca8d, R9 - MOVQ $0xb85045b68181585d, R10 - MOVQ $0x30644e72e131a029, R11 - CMOVQCC DI, R8 - CMOVQCC DI, R9 - CMOVQCC DI, R10 - CMOVQCC DI, R11 - ADDQ R8, AX - ADCQ R9, DX - ADCQ R10, CX - ADCQ R11, BX - MOVQ res+0(FP), R12 - MOVQ AX, 0(R12) - MOVQ DX, 8(R12) - MOVQ CX, 16(R12) - MOVQ BX, 24(R12) - RET - -// double(res, x *Element) -TEXT ·double(SB), NOSPLIT, $0-16 - MOVQ x+8(FP), AX - MOVQ 0(AX), DX - MOVQ 8(AX), CX - MOVQ 16(AX), BX - MOVQ 24(AX), SI - ADDQ DX, DX - ADCQ CX, CX - ADCQ BX, BX - ADCQ SI, SI - - // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) - REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) - - MOVQ res+0(FP), R11 - MOVQ DX, 0(R11) - MOVQ CX, 8(R11) - MOVQ BX, 16(R11) - MOVQ SI, 24(R11) - RET - -// neg(res, x *Element) -TEXT ·neg(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DI - MOVQ x+8(FP), AX - MOVQ 0(AX), DX - MOVQ 8(AX), CX - MOVQ 16(AX), BX - MOVQ 24(AX), SI - MOVQ DX, AX - ORQ CX, AX - ORQ BX, AX - ORQ SI, AX - TESTQ AX, AX - JEQ l1 - MOVQ $0x3c208c16d87cfd47, R8 - SUBQ DX, R8 - MOVQ R8, 0(DI) - MOVQ $0x97816a916871ca8d, R8 - SBBQ CX, R8 - MOVQ R8, 8(DI) - MOVQ $0xb85045b68181585d, R8 - SBBQ BX, R8 - MOVQ R8, 16(DI) - MOVQ $0x30644e72e131a029, R8 - SBBQ SI, R8 - MOVQ R8, 24(DI) - RET - -l1: - MOVQ AX, 0(DI) - MOVQ AX, 8(DI) - MOVQ AX, 16(DI) - MOVQ AX, 24(DI) - RET - TEXT ·reduce(SB), NOSPLIT, $0-8 MOVQ res+0(FP), AX MOVQ 0(AX), DX diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_noasm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_noasm.go deleted file mode 100644 index fec62891833..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_noasm.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build !amd64 -// +build !amd64 - -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fp - -// /!\ WARNING /!\ -// this code has not been audited and is provided as-is. In particular, -// there is no security guarantees such as constant time implementation -// or side-channel attack resistance -// /!\ WARNING /!\ - -// MulBy3 x *= 3 -func MulBy3(x *Element) { - mulByConstant(x, 3) -} - -// MulBy5 x *= 5 -func MulBy5(x *Element) { - mulByConstant(x, 5) -} - -// MulBy13 x *= 13 -func MulBy13(x *Element) { - mulByConstant(x, 13) -} - -// Butterfly sets -// a = a + b -// b = a - b -func Butterfly(a, b *Element) { - _butterflyGeneric(a, b) -} - -func mul(z, x, y *Element) { - _mulGeneric(z, x, y) -} - -// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation -// sets and returns z = z * 1 -func fromMont(z *Element) { - _fromMontGeneric(z) -} - -func add(z, x, y *Element) { - _addGeneric(z, x, y) -} - -func double(z, x *Element) { - _doubleGeneric(z, x) -} - -func sub(z, x, y *Element) { - _subGeneric(z, x, y) -} - -func neg(z, x *Element) { - _negGeneric(z, x) -} - -func reduce(z *Element) { - _reduceGeneric(z) -} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_purego.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_purego.go new file mode 100644 index 00000000000..93aca54ddb4 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element_ops_purego.go @@ -0,0 +1,443 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import "math/bits" + +// MulBy3 x *= 3 (mod q) +func MulBy3(x *Element) { + _x := *x + x.Double(x).Add(x, &_x) +} + +// MulBy5 x *= 5 (mod q) +func MulBy5(x *Element) { + _x := *x + x.Double(x).Double(x).Add(x, &_x) +} + +// MulBy13 x *= 13 (mod q) +func MulBy13(x *Element) { + var y = Element{ + 529957932336199972, + 13952065197595570812, + 769406925088786211, + 2691790815622165739, + } + x.Mul(x, &y) +} + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, y[0]) + u1, t1 = bits.Mul64(v, y[1]) + u2, t2 = bits.Mul64(v, y[2]) + u3, t3 = bits.Mul64(v, y[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for algorithm documentation + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, x[0]) + u1, t1 = bits.Mul64(v, x[1]) + u2, t2 = bits.Mul64(v, x[2]) + u3, t3 = bits.Mul64(v, x[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/vector.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/vector.go new file mode 100644 index 00000000000..acf1e44ea92 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/vector.go @@ -0,0 +1,253 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fp + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "runtime" + "strings" + "sync" + "sync/atomic" + "unsafe" +) + +// Vector represents a slice of Element. +// +// It implements the following interfaces: +// - Stringer +// - io.WriterTo +// - io.ReaderFrom +// - encoding.BinaryMarshaler +// - encoding.BinaryUnmarshaler +// - sort.Interface +type Vector []Element + +// MarshalBinary implements encoding.BinaryMarshaler +func (vector *Vector) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + + if _, err = vector.WriteTo(&buf); err != nil { + return + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (vector *Vector) UnmarshalBinary(data []byte) error { + r := bytes.NewReader(data) + _, err := vector.ReadFrom(r) + return err +} + +// WriteTo implements io.WriterTo and writes a vector of big endian encoded Element. +// Length of the vector is encoded as a uint32 on the first 4 bytes. +func (vector *Vector) WriteTo(w io.Writer) (int64, error) { + // encode slice length + if err := binary.Write(w, binary.BigEndian, uint32(len(*vector))); err != nil { + return 0, err + } + + n := int64(4) + + var buf [Bytes]byte + for i := 0; i < len(*vector); i++ { + BigEndian.PutElement(&buf, (*vector)[i]) + m, err := w.Write(buf[:]) + n += int64(m) + if err != nil { + return n, err + } + } + return n, nil +} + +// AsyncReadFrom reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +// It consumes the needed bytes from the reader and returns the number of bytes read and an error if any. +// It also returns a channel that will be closed when the validation is done. +// The validation consist of checking that the elements are smaller than the modulus, and +// converting them to montgomery form. +func (vector *Vector) AsyncReadFrom(r io.Reader) (int64, error, chan error) { + chErr := make(chan error, 1) + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + close(chErr) + return int64(read), err, chErr + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + if sliceLen == 0 { + close(chErr) + return n, nil, chErr + } + + bSlice := unsafe.Slice((*byte)(unsafe.Pointer(&(*vector)[0])), sliceLen*Bytes) + read, err := io.ReadFull(r, bSlice) + n += int64(read) + if err != nil { + close(chErr) + return n, err, chErr + } + + go func() { + var cptErrors uint64 + // process the elements in parallel + execute(int(sliceLen), func(start, end int) { + + var z Element + for i := start; i < end; i++ { + // we have to set vector[i] + bstart := i * Bytes + bend := bstart + Bytes + b := bSlice[bstart:bend] + z[0] = binary.BigEndian.Uint64(b[24:32]) + z[1] = binary.BigEndian.Uint64(b[16:24]) + z[2] = binary.BigEndian.Uint64(b[8:16]) + z[3] = binary.BigEndian.Uint64(b[0:8]) + + if !z.smallerThanModulus() { + atomic.AddUint64(&cptErrors, 1) + return + } + z.toMont() + (*vector)[i] = z + } + }) + + if cptErrors > 0 { + chErr <- fmt.Errorf("async read: %d elements failed validation", cptErrors) + } + close(chErr) + }() + return n, nil, chErr +} + +// ReadFrom implements io.ReaderFrom and reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +func (vector *Vector) ReadFrom(r io.Reader) (int64, error) { + + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + return int64(read), err + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + + for i := 0; i < int(sliceLen); i++ { + read, err := io.ReadFull(r, buf[:]) + n += int64(read) + if err != nil { + return n, err + } + (*vector)[i], err = BigEndian.Element(&buf) + if err != nil { + return n, err + } + } + + return n, nil +} + +// String implements fmt.Stringer interface +func (vector Vector) String() string { + var sbb strings.Builder + sbb.WriteByte('[') + for i := 0; i < len(vector); i++ { + sbb.WriteString(vector[i].String()) + if i != len(vector)-1 { + sbb.WriteByte(',') + } + } + sbb.WriteByte(']') + return sbb.String() +} + +// Len is the number of elements in the collection. +func (vector Vector) Len() int { + return len(vector) +} + +// Less reports whether the element with +// index i should sort before the element with index j. +func (vector Vector) Less(i, j int) bool { + return vector[i].Cmp(&vector[j]) == -1 +} + +// Swap swaps the elements with indexes i and j. +func (vector Vector) Swap(i, j int) { + vector[i], vector[j] = vector[j], vector[i] +} + +// TODO @gbotrel make a public package out of that. +// execute executes the work function in parallel. +// this is copy paste from internal/parallel/parallel.go +// as we don't want to generate code importing internal/ +func execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + if nbTasks < 1 { + nbTasks = 1 + } else if nbTasks > 512 { + nbTasks = 512 + } + } + + if nbTasks == 1 { + // no go routines + work(0, nbIterations) + return + } + + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/arith.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/arith.go index 83c9fd9ef91..7cfd55da199 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/arith.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/arith.go @@ -58,3 +58,16 @@ func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { hi, _ = bits.Add64(hi, e, carry) return } +func max(a int, b int) int { + if a > b { + return a + } + return b +} + +func min(a int, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm.go index 8241357c459..da061913ba7 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm.go @@ -21,4 +21,7 @@ package fr import "golang.org/x/sys/cpu" -var supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 +var ( + supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm_noadx.go index 221beab937e..7f52ffa197b 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm_noadx.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/asm_noadx.go @@ -22,4 +22,7 @@ package fr // note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag // certain errors (like fatal error: missing stackmap) // this ensures we test all asm path. -var supportAdx = false +var ( + supportAdx = false + _ = supportAdx +) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/doc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/doc.go index e1dea9c74e4..35388f880f8 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/doc.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/doc.go @@ -21,23 +21,33 @@ // The modulus is hardcoded in all the operations. // // Field elements are represented as an array, and assumed to be in Montgomery form in all methods: -// type Element [4]uint64 // -// Example API signature -// // Mul z = x * y mod q -// func (z *Element) Mul(x, y *Element) *Element +// type Element [4]uint64 +// +// # Usage +// +// Example API signature: +// +// // Mul z = x * y (mod q) +// func (z *Element) Mul(x, y *Element) *Element // // and can be used like so: -// var a, b Element -// a.SetUint64(2) -// b.SetString("984896738") -// a.Mul(a, b) -// a.Sub(a, a) -// .Add(a, b) -// .Inv(a) -// b.Exp(b, new(big.Int).SetUint64(42)) -// -// Modulus -// 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 // base 16 -// 21888242871839275222246405745257275088548364400416034343698204186575808495617 // base 10 +// +// var a, b Element +// a.SetUint64(2) +// b.SetString("984896738") +// a.Mul(a, b) +// a.Sub(a, a) +// .Add(a, b) +// .Inv(a) +// b.Exp(b, new(big.Int).SetUint64(42)) +// +// Modulus q = +// +// q[base10] = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +// q[base16] = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. package fr diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element.go index b323c190684..cda0b2c2885 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element.go @@ -16,12 +16,6 @@ package fr -// /!\ WARNING /!\ -// this code has not been audited and is provided as-is. In particular, -// there is no security guarantees such as constant time implementation -// or side-channel attack resistance -// /!\ WARNING /!\ - import ( "crypto/rand" "encoding/binary" @@ -32,75 +26,71 @@ import ( "reflect" "strconv" "strings" - "sync" + + "github.com/bits-and-blooms/bitset" + "github.com/consensys/gnark-crypto/field/hash" + "github.com/consensys/gnark-crypto/field/pool" ) // Element represents a field element stored on 4 words (uint64) -// Element are assumed to be in Montgomery form in all methods -// field modulus q = // -// 21888242871839275222246405745257275088548364400416034343698204186575808495617 +// Element are assumed to be in Montgomery form in all methods. +// +// Modulus q = +// +// q[base10] = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +// q[base16] = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// +// # Warning +// +// This code has not been audited and is provided as-is. In particular, there is no security guarantees such as constant time implementation or side-channel attack resistance. type Element [4]uint64 -// Limbs number of 64 bits words needed to represent Element -const Limbs = 4 +const ( + Limbs = 4 // number of 64 bits words needed to represent a Element + Bits = 254 // number of bits needed to represent a Element + Bytes = 32 // number of bytes needed to represent a Element +) -// Bits number bits needed to represent Element -const Bits = 254 +// Field modulus q +const ( + q0 uint64 = 4891460686036598785 + q1 uint64 = 2896914383306846353 + q2 uint64 = 13281191951274694749 + q3 uint64 = 3486998266802970665 +) -// Bytes number bytes needed to represent Element -const Bytes = Limbs * 8 +var qElement = Element{ + q0, + q1, + q2, + q3, +} -// field modulus stored as big.Int -var _modulus big.Int +var _modulus big.Int // q stored as big.Int // Modulus returns q as a big.Int -// q = // -// 21888242871839275222246405745257275088548364400416034343698204186575808495617 +// q[base10] = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +// q[base16] = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 func Modulus() *big.Int { return new(big.Int).Set(&_modulus) } -// q (modulus) -const qElementWord0 uint64 = 4891460686036598785 -const qElementWord1 uint64 = 2896914383306846353 -const qElementWord2 uint64 = 13281191951274694749 -const qElementWord3 uint64 = 3486998266802970665 - -var qElement = Element{ - qElementWord0, - qElementWord1, - qElementWord2, - qElementWord3, -} - -// Used for Montgomery reduction. (qInvNeg) q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r -const qInvNegLsw uint64 = 14042775128853446655 - -// rSquare -var rSquare = Element{ - 1997599621687373223, - 6052339484930628067, - 10108755138030829701, - 150537098327114917, -} - -var bigIntPool = sync.Pool{ - New: func() interface{} { - return new(big.Int) - }, -} +// q + r'.r = 1, i.e., qInvNeg = - q⁻¹ mod r +// used for Montgomery reduction +const qInvNeg uint64 = 14042775128853446655 func init() { - _modulus.SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10) + _modulus.SetString("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", 16) } // NewElement returns a new Element from a uint64 value // // it is equivalent to -// var v NewElement -// v.SetUint64(...) +// +// var v Element +// v.SetUint64(...) func NewElement(v uint64) Element { z := Element{v} z.Mul(&z, &rSquare) @@ -111,7 +101,7 @@ func NewElement(v uint64) Element { func (z *Element) SetUint64(v uint64) *Element { // sets z LSB to v (non-Montgomery form) and convert z to Montgomery form *z = Element{v} - return z.Mul(z, &rSquare) // z.ToMont() + return z.Mul(z, &rSquare) // z.toMont() } // SetInt64 sets z to v and returns z @@ -129,7 +119,7 @@ func (z *Element) SetInt64(v int64) *Element { return z } -// Set z = x +// Set z = x and returns z func (z *Element) Set(x *Element) *Element { z[0] = x[0] z[1] = x[1] @@ -140,13 +130,28 @@ func (z *Element) Set(x *Element) *Element { // SetInterface converts provided interface into Element // returns an error if provided type is not supported -// supported types: Element, *Element, uint64, int, string (interpreted as base10 integer), -// *big.Int, big.Int, []byte +// supported types: +// +// Element +// *Element +// uint64 +// int +// string (see SetString for valid formats) +// *big.Int +// big.Int +// []byte func (z *Element) SetInterface(i1 interface{}) (*Element, error) { + if i1 == nil { + return nil, errors.New("can't set fr.Element with ") + } + switch c1 := i1.(type) { case Element: return z.Set(&c1), nil case *Element: + if c1 == nil { + return nil, errors.New("can't set fr.Element with ") + } return z.Set(c1), nil case uint8: return z.SetUint64(uint64(c1)), nil @@ -169,8 +174,11 @@ func (z *Element) SetInterface(i1 interface{}) (*Element, error) { case int: return z.SetInt64(int64(c1)), nil case string: - return z.SetString(c1), nil + return z.SetString(c1) case *big.Int: + if c1 == nil { + return nil, errors.New("can't set fr.Element with ") + } return z.SetBigInt(c1), nil case big.Int: return z.SetBigInt(&c1), nil @@ -199,7 +207,7 @@ func (z *Element) SetOne() *Element { return z } -// Div z = x*y^-1 mod q +// Div z = x*y⁻¹ (mod q) func (z *Element) Div(x, y *Element) *Element { var yInv Element yInv.Inverse(y) @@ -207,19 +215,14 @@ func (z *Element) Div(x, y *Element) *Element { return z } -// Bit returns the i'th bit, with lsb == bit 0. -// It is the responsability of the caller to convert from Montgomery to Regular form if needed -func (z *Element) Bit(i uint64) uint64 { - j := i / 64 - if j >= 4 { - return 0 - } - return uint64(z[j] >> (i % 64) & 1) +// Equal returns z == x; constant-time +func (z *Element) Equal(x *Element) bool { + return z.NotEqual(x) == 0 } -// Equal returns z == x -func (z *Element) Equal(x *Element) bool { - return (z[3] == x[3]) && (z[2] == x[2]) && (z[1] == x[1]) && (z[0] == x[0]) +// NotEqual returns 0 if and only if z == x; constant-time +func (z *Element) NotEqual(x *Element) uint64 { + return (z[3] ^ x[3]) | (z[2] ^ x[2]) | (z[1] ^ x[1]) | (z[0] ^ x[0]) } // IsZero returns z == 0 @@ -227,22 +230,38 @@ func (z *Element) IsZero() bool { return (z[3] | z[2] | z[1] | z[0]) == 0 } +// IsOne returns z == 1 +func (z *Element) IsOne() bool { + return ((z[3] ^ 1011752739694698287) | (z[2] ^ 7381016538464732718) | (z[1] ^ 3962172157175319849) | (z[0] ^ 12436184717236109307)) == 0 +} + // IsUint64 reports whether z can be represented as an uint64. func (z *Element) IsUint64() bool { + zz := *z + zz.fromMont() + return zz.FitsOnOneWord() +} + +// Uint64 returns the uint64 representation of x. If x cannot be represented in a uint64, the result is undefined. +func (z *Element) Uint64() uint64 { + return z.Bits()[0] +} + +// FitsOnOneWord reports whether z words (except the least significant word) are 0 +// +// It is the responsibility of the caller to convert from Montgomery to Regular form if needed. +func (z *Element) FitsOnOneWord() bool { return (z[3] | z[2] | z[1]) == 0 } // Cmp compares (lexicographic order) z and x and returns: // -// -1 if z < x -// 0 if z == x -// +1 if z > x -// +// -1 if z < x +// 0 if z == x +// +1 if z > x func (z *Element) Cmp(x *Element) int { - _z := *z - _x := *x - _z.FromMont() - _x.FromMont() + _z := z.Bits() + _x := x.Bits() if _z[3] > _x[3] { return 1 } else if _z[3] < _x[3] { @@ -273,8 +292,7 @@ func (z *Element) LexicographicallyLargest() bool { // we check if the element is larger than (q-1) / 2 // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 - _z := *z - _z.FromMont() + _z := z.Bits() var b uint64 _, b = bits.Sub64(_z[0], 11669102379873075201, 0) @@ -285,53 +303,79 @@ func (z *Element) LexicographicallyLargest() bool { return b == 0 } -// SetRandom sets z to a random element < q +// SetRandom sets z to a uniform random value in [0, q). +// +// This might error only if reading from crypto/rand.Reader errors, +// in which case, value of z is undefined. func (z *Element) SetRandom() (*Element, error) { - var bytes [32]byte - if _, err := io.ReadFull(rand.Reader, bytes[:]); err != nil { - return nil, err + // this code is generated for all modulus + // and derived from go/src/crypto/rand/util.go + + // l is number of limbs * 8; the number of bytes needed to reconstruct 4 uint64 + const l = 32 + + // bitLen is the maximum bit length needed to encode a value < q. + const bitLen = 254 + + // k is the maximum byte length needed to encode a value < q. + const k = (bitLen + 7) / 8 + + // b is the number of bits in the most significant byte of q-1. + b := uint(bitLen % 8) + if b == 0 { + b = 8 } - z[0] = binary.BigEndian.Uint64(bytes[0:8]) - z[1] = binary.BigEndian.Uint64(bytes[8:16]) - z[2] = binary.BigEndian.Uint64(bytes[16:24]) - z[3] = binary.BigEndian.Uint64(bytes[24:32]) - z[3] %= 3486998266802970665 - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + var bytes [l]byte + + for { + // note that bytes[k:l] is always 0 + if _, err := io.ReadFull(rand.Reader, bytes[:k]); err != nil { + return nil, err + } + + // Clear unused bits in in the most significant byte to increase probability + // that the candidate is < q. + bytes[k-1] &= uint8(int(1<> 1 - z[0] = z[0]>>1 | z[1]<<63 z[1] = z[1]>>1 | z[2]<<63 z[2] = z[2]>>1 | z[3]<<63 @@ -339,323 +383,305 @@ func (z *Element) Halve() { } -// API with assembly impl - -// Mul z = x * y mod q -// see https://hackmd.io/@gnark/modular_multiplication -func (z *Element) Mul(x, y *Element) *Element { - mul(z, x, y) - return z -} - -// Square z = x * x mod q -// see https://hackmd.io/@gnark/modular_multiplication -func (z *Element) Square(x *Element) *Element { - mul(z, x, x) - return z -} - -// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// fromMont converts z in place (i.e. mutates) from Montgomery to regular representation // sets and returns z = z * 1 -func (z *Element) FromMont() *Element { +func (z *Element) fromMont() *Element { fromMont(z) return z } -// Add z = x + y mod q +// Add z = x + y (mod q) func (z *Element) Add(x, y *Element) *Element { - add(z, x, y) + + var carry uint64 + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], _ = bits.Add64(x[3], y[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } return z } -// Double z = x + x mod q, aka Lsh 1 +// Double z = x + x (mod q), aka Lsh 1 func (z *Element) Double(x *Element) *Element { - double(z, x) + + var carry uint64 + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], _ = bits.Add64(x[3], x[3], carry) + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } return z } -// Sub z = x - y mod q +// Sub z = x - y (mod q) func (z *Element) Sub(x, y *Element) *Element { - sub(z, x, y) + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], q0, 0) + z[1], c = bits.Add64(z[1], q1, c) + z[2], c = bits.Add64(z[2], q2, c) + z[3], _ = bits.Add64(z[3], q3, c) + } return z } // Neg z = q - x func (z *Element) Neg(x *Element) *Element { - neg(z, x) + if x.IsZero() { + z.SetZero() + return z + } + var borrow uint64 + z[0], borrow = bits.Sub64(q0, x[0], 0) + z[1], borrow = bits.Sub64(q1, x[1], borrow) + z[2], borrow = bits.Sub64(q2, x[2], borrow) + z[3], _ = bits.Sub64(q3, x[3], borrow) return z } -// Generic (no ADX instructions, no AMD64) versions of multiplication and squaring algorithms +// Select is a constant-time conditional move. +// If c=0, z = x0. Else z = x1 +func (z *Element) Select(c int, x0 *Element, x1 *Element) *Element { + cC := uint64((int64(c) | -int64(c)) >> 63) // "canonicized" into: 0 if c=0, -1 otherwise + z[0] = x0[0] ^ cC&(x0[0]^x1[0]) + z[1] = x0[1] ^ cC&(x0[1]^x1[1]) + z[2] = x0[2] ^ cC&(x0[2]^x1[2]) + z[3] = x0[3] ^ cC&(x0[3]^x1[3]) + return z +} +// _mulGeneric is unoptimized textbook CIOS +// it is a fallback solution on x86 when ADX instruction set is not available +// and is used for testing purposes. func _mulGeneric(z, x, y *Element) { - var t [4]uint64 - var c [3]uint64 - { - // round 0 - v := x[0] - c[1], c[0] = bits.Mul64(v, y[0]) - m := c[0] * 14042775128853446655 - c[2] = madd0(m, 4891460686036598785, c[0]) - c[1], c[0] = madd1(v, y[1], c[1]) - c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0]) - c[1], c[0] = madd1(v, y[2], c[1]) - c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd1(v, y[3], c[1]) - t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - { - // round 1 - v := x[1] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 14042775128853446655 - c[2] = madd0(m, 4891460686036598785, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - { - // round 2 - v := x[2] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 14042775128853446655 - c[2] = madd0(m, 4891460686036598785, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - { - // round 3 - v := x[3] - c[1], c[0] = madd1(v, y[0], t[0]) - m := c[0] * 14042775128853446655 - c[2] = madd0(m, 4891460686036598785, c[0]) - c[1], c[0] = madd2(v, y[1], c[1], t[1]) - c[2], z[0] = madd2(m, 2896914383306846353, c[2], c[0]) - c[1], c[0] = madd2(v, y[2], c[1], t[2]) - c[2], z[1] = madd2(m, 13281191951274694749, c[2], c[0]) - c[1], c[0] = madd2(v, y[3], c[1], t[3]) - z[3], z[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1]) - } - - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + + var t [5]uint64 + var D uint64 + var m, C uint64 + // ----------------------------------- + // First loop + + C, t[0] = bits.Mul64(y[0], x[0]) + C, t[1] = madd1(y[0], x[1], C) + C, t[2] = madd1(y[0], x[2], C) + C, t[3] = madd1(y[0], x[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[1], x[0], t[0]) + C, t[1] = madd2(y[1], x[1], t[1], C) + C, t[2] = madd2(y[1], x[2], t[2], C) + C, t[3] = madd2(y[1], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[2], x[0], t[0]) + C, t[1] = madd2(y[2], x[1], t[1], C) + C, t[2] = madd2(y[2], x[2], t[2], C) + C, t[3] = madd2(y[2], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + // ----------------------------------- + // First loop + + C, t[0] = madd1(y[3], x[0], t[0]) + C, t[1] = madd2(y[3], x[1], t[1], C) + C, t[2] = madd2(y[3], x[2], t[2], C) + C, t[3] = madd2(y[3], x[3], t[3], C) + + t[4], D = bits.Add64(t[4], C, 0) + + // m = t[0]n'[0] mod W + m = t[0] * qInvNeg + + // ----------------------------------- + // Second loop + C = madd0(m, q0, t[0]) + C, t[0] = madd2(m, q1, t[1], C) + C, t[1] = madd2(m, q2, t[2], C) + C, t[2] = madd2(m, q3, t[3], C) + + t[3], C = bits.Add64(t[4], C, 0) + t[4], _ = bits.Add64(0, D, C) + + if t[4] != 0 { + // we need to reduce, we have a result on 5 words var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(t[0], q0, 0) + z[1], b = bits.Sub64(t[1], q1, b) + z[2], b = bits.Sub64(t[2], q2, b) + z[3], _ = bits.Sub64(t[3], q3, b) + return } -} - -func _mulWGeneric(z, x *Element, y uint64) { - var t [4]uint64 - { - // round 0 - c1, c0 := bits.Mul64(y, x[0]) - m := c0 * 14042775128853446655 - c2 := madd0(m, 4891460686036598785, c0) - c1, c0 = madd1(y, x[1], c1) - c2, t[0] = madd2(m, 2896914383306846353, c2, c0) - c1, c0 = madd1(y, x[2], c1) - c2, t[1] = madd2(m, 13281191951274694749, c2, c0) - c1, c0 = madd1(y, x[3], c1) - t[3], t[2] = madd3(m, 3486998266802970665, c0, c2, c1) - } - { - // round 1 - m := t[0] * 14042775128853446655 - c2 := madd0(m, 4891460686036598785, t[0]) - c2, t[0] = madd2(m, 2896914383306846353, c2, t[1]) - c2, t[1] = madd2(m, 13281191951274694749, c2, t[2]) - t[3], t[2] = madd2(m, 3486998266802970665, t[3], c2) - } - { - // round 2 - m := t[0] * 14042775128853446655 - c2 := madd0(m, 4891460686036598785, t[0]) - c2, t[0] = madd2(m, 2896914383306846353, c2, t[1]) - c2, t[1] = madd2(m, 13281191951274694749, c2, t[2]) - t[3], t[2] = madd2(m, 3486998266802970665, t[3], c2) - } - { - // round 3 - m := t[0] * 14042775128853446655 - c2 := madd0(m, 4891460686036598785, t[0]) - c2, z[0] = madd2(m, 2896914383306846353, c2, t[1]) - c2, z[1] = madd2(m, 13281191951274694749, c2, t[2]) - z[3], z[2] = madd2(m, 3486998266802970665, t[3], c2) - } + // copy t into z + z[0] = t[0] + z[1] = t[1] + z[2] = t[2] + z[3] = t[3] - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } } func _fromMontGeneric(z *Element) { // the following lines implement z = z * 1 // with a modified CIOS montgomery multiplication + // see Mul for algorithm documentation { // m = z[0]n'[0] mod W - m := z[0] * 14042775128853446655 - C := madd0(m, 4891460686036598785, z[0]) - C, z[0] = madd2(m, 2896914383306846353, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } { // m = z[0]n'[0] mod W - m := z[0] * 14042775128853446655 - C := madd0(m, 4891460686036598785, z[0]) - C, z[0] = madd2(m, 2896914383306846353, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } { // m = z[0]n'[0] mod W - m := z[0] * 14042775128853446655 - C := madd0(m, 4891460686036598785, z[0]) - C, z[0] = madd2(m, 2896914383306846353, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } { // m = z[0]n'[0] mod W - m := z[0] * 14042775128853446655 - C := madd0(m, 4891460686036598785, z[0]) - C, z[0] = madd2(m, 2896914383306846353, z[1], C) - C, z[1] = madd2(m, 13281191951274694749, z[2], C) - C, z[2] = madd2(m, 3486998266802970665, z[3], C) + m := z[0] * qInvNeg + C := madd0(m, q0, z[0]) + C, z[0] = madd2(m, q1, z[1], C) + C, z[1] = madd2(m, q2, z[2], C) + C, z[2] = madd2(m, q3, z[3], C) z[3] = C } - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } } -func _addGeneric(z, x, y *Element) { - var carry uint64 - - z[0], carry = bits.Add64(x[0], y[0], 0) - z[1], carry = bits.Add64(x[1], y[1], carry) - z[2], carry = bits.Add64(x[2], y[2], carry) - z[3], _ = bits.Add64(x[3], y[3], carry) - - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) - } -} - -func _doubleGeneric(z, x *Element) { - var carry uint64 - - z[0], carry = bits.Add64(x[0], x[0], 0) - z[1], carry = bits.Add64(x[1], x[1], carry) - z[2], carry = bits.Add64(x[2], x[2], carry) - z[3], _ = bits.Add64(x[3], x[3], carry) - - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { - var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) - } -} - -func _subGeneric(z, x, y *Element) { - var b uint64 - z[0], b = bits.Sub64(x[0], y[0], 0) - z[1], b = bits.Sub64(x[1], y[1], b) - z[2], b = bits.Sub64(x[2], y[2], b) - z[3], b = bits.Sub64(x[3], y[3], b) - if b != 0 { - var c uint64 - z[0], c = bits.Add64(z[0], 4891460686036598785, 0) - z[1], c = bits.Add64(z[1], 2896914383306846353, c) - z[2], c = bits.Add64(z[2], 13281191951274694749, c) - z[3], _ = bits.Add64(z[3], 3486998266802970665, c) - } -} - -func _negGeneric(z, x *Element) { - if x.IsZero() { - z.SetZero() - return - } - var borrow uint64 - z[0], borrow = bits.Sub64(4891460686036598785, x[0], 0) - z[1], borrow = bits.Sub64(2896914383306846353, x[1], borrow) - z[2], borrow = bits.Sub64(13281191951274694749, x[2], borrow) - z[3], _ = bits.Sub64(3486998266802970665, x[3], borrow) -} - func _reduceGeneric(z *Element) { - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) - } -} - -func mulByConstant(z *Element, c uint8) { - switch c { - case 0: - z.SetZero() - return - case 1: - return - case 2: - z.Double(z) - return - case 3: - _z := *z - z.Double(z).Add(z, &_z) - case 5: - _z := *z - z.Double(z).Double(z).Add(z, &_z) - default: - var y Element - y.SetUint64(uint64(c)) - z.Mul(z, &y) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } } @@ -667,12 +693,12 @@ func BatchInvert(a []Element) []Element { return res } - zeroes := make([]bool, len(a)) + zeroes := bitset.New(uint(len(a))) accumulator := One() for i := 0; i < len(a); i++ { if a[i].IsZero() { - zeroes[i] = true + zeroes.Set(uint(i)) continue } res[i] = accumulator @@ -682,7 +708,7 @@ func BatchInvert(a []Element) []Element { accumulator.Inverse(&accumulator) for i := len(a) - 1; i >= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -713,18 +739,59 @@ func (z *Element) BitLen() int { return bits.Len64(z[0]) } -// Exp z = x^exponent mod q -func (z *Element) Exp(x Element, exponent *big.Int) *Element { - var bZero big.Int - if exponent.Cmp(&bZero) == 0 { +// Hash msg to count prime field elements. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 +func Hash(msg, dst []byte, count int) ([]Element, error) { + // 128 bits of security + // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 + const Bytes = 1 + (Bits-1)/8 + const L = 16 + Bytes + + lenInBytes := count * L + pseudoRandomBytes, err := hash.ExpandMsgXmd(msg, dst, lenInBytes) + if err != nil { + return nil, err + } + + // get temporary big int from the pool + vv := pool.BigInt.Get() + + res := make([]Element, count) + for i := 0; i < count; i++ { + vv.SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) + res[i].SetBigInt(vv) + } + + // release object into pool + pool.BigInt.Put(vv) + + return res, nil +} + +// Exp z = xᵏ (mod q) +func (z *Element) Exp(x Element, k *big.Int) *Element { + if k.IsUint64() && k.Uint64() == 0 { return z.SetOne() } + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q) == (x⁻¹)ᵏ (mod q) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = pool.BigInt.Get() + defer pool.BigInt.Put(e) + e.Neg(k) + } + z.Set(&x) - for i := exponent.BitLen() - 2; i >= 0; i-- { + for i := e.BitLen() - 2; i >= 0; i-- { z.Square(z) - if exponent.Bit(i) == 1 { + if e.Bit(i) == 1 { z.Mul(z, &x) } } @@ -732,15 +799,20 @@ func (z *Element) Exp(x Element, exponent *big.Int) *Element { return z } -// ToMont converts z to Montgomery form -// sets and returns z = z * r² -func (z *Element) ToMont() *Element { - return z.Mul(z, &rSquare) +// rSquare where r is the Montgommery constant +// see section 2.3.2 of Tolga Acar's thesis +// https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf +var rSquare = Element{ + 1997599621687373223, + 6052339484930628067, + 10108755138030829701, + 150537098327114917, } -// ToRegular returns z in regular form (doesn't mutate z) -func (z Element) ToRegular() Element { - return *z.FromMont() +// toMont converts z to Montgomery form +// sets and returns z = z * r² +func (z *Element) toMont() *Element { + return z.Mul(z, &rSquare) } // String returns the decimal representation of z as generated by @@ -749,12 +821,23 @@ func (z *Element) String() string { return z.Text(10) } +// toBigInt returns z as a big.Int in Montgomery form +func (z *Element) toBigInt(res *big.Int) *big.Int { + var b [Bytes]byte + binary.BigEndian.PutUint64(b[24:32], z[0]) + binary.BigEndian.PutUint64(b[16:24], z[1]) + binary.BigEndian.PutUint64(b[8:16], z[2]) + binary.BigEndian.PutUint64(b[0:8], z[3]) + + return res.SetBytes(b[:]) +} + // Text returns the string representation of z in the given base. // Base must be between 2 and 36, inclusive. The result uses the // lower-case letters 'a' to 'z' for digit values 10 to 35. // No prefix (such as "0x") is added to the string. If z is a nil // pointer it returns "". -// If base == 10 and -z fits in a uint64 prefix "-" is added to the string. +// If base == 10 and -z fits in a uint16 prefix "-" is added to the string. func (z *Element) Text(base int) string { if base < 2 || base > 36 { panic("invalid base") @@ -762,77 +845,110 @@ func (z *Element) Text(base int) string { if z == nil { return "" } - zz := *z - zz.FromMont() - if zz.IsUint64() { - return strconv.FormatUint(zz[0], base) - } else if base == 10 { + + const maxUint16 = 65535 + if base == 10 { var zzNeg Element zzNeg.Neg(z) - zzNeg.FromMont() - if zzNeg.IsUint64() { + zzNeg.fromMont() + if zzNeg.FitsOnOneWord() && zzNeg[0] <= maxUint16 && zzNeg[0] != 0 { return "-" + strconv.FormatUint(zzNeg[0], base) } } - vv := bigIntPool.Get().(*big.Int) - r := zz.ToBigInt(vv).Text(base) - bigIntPool.Put(vv) + zz := *z + zz.fromMont() + if zz.FitsOnOneWord() { + return strconv.FormatUint(zz[0], base) + } + vv := pool.BigInt.Get() + r := zz.toBigInt(vv).Text(base) + pool.BigInt.Put(vv) return r } -// ToBigInt returns z as a big.Int in Montgomery form -func (z *Element) ToBigInt(res *big.Int) *big.Int { - var b [Limbs * 8]byte - binary.BigEndian.PutUint64(b[24:32], z[0]) - binary.BigEndian.PutUint64(b[16:24], z[1]) - binary.BigEndian.PutUint64(b[8:16], z[2]) - binary.BigEndian.PutUint64(b[0:8], z[3]) - - return res.SetBytes(b[:]) +// BigInt sets and return z as a *big.Int +func (z *Element) BigInt(res *big.Int) *big.Int { + _z := *z + _z.fromMont() + return _z.toBigInt(res) } // ToBigIntRegular returns z as a big.Int in regular form +// +// Deprecated: use BigInt(*big.Int) instead func (z Element) ToBigIntRegular(res *big.Int) *big.Int { - z.FromMont() - return z.ToBigInt(res) + z.fromMont() + return z.toBigInt(res) } -// Bytes returns the regular (non montgomery) value -// of z as a big-endian byte array. -func (z *Element) Bytes() (res [Limbs * 8]byte) { - _z := z.ToRegular() - binary.BigEndian.PutUint64(res[24:32], _z[0]) - binary.BigEndian.PutUint64(res[16:24], _z[1]) - binary.BigEndian.PutUint64(res[8:16], _z[2]) - binary.BigEndian.PutUint64(res[0:8], _z[3]) +// Bits provides access to z by returning its value as a little-endian [4]uint64 array. +// Bits is intended to support implementation of missing low-level Element +// functionality outside this package; it should be avoided otherwise. +func (z *Element) Bits() [4]uint64 { + _z := *z + fromMont(&_z) + return _z +} +// Bytes returns the value of z as a big-endian byte array +func (z *Element) Bytes() (res [Bytes]byte) { + BigEndian.PutElement(&res, *z) return } -// Marshal returns the regular (non montgomery) value -// of z as a big-endian byte slice. +// Marshal returns the value of z as a big-endian byte slice func (z *Element) Marshal() []byte { b := z.Bytes() return b[:] } +// Unmarshal is an alias for SetBytes, it sets z to the value of e. +func (z *Element) Unmarshal(e []byte) { + z.SetBytes(e) +} + // SetBytes interprets e as the bytes of a big-endian unsigned integer, -// sets z to that value (in Montgomery form), and returns z. +// sets z to that value, and returns z. func (z *Element) SetBytes(e []byte) *Element { + if len(e) == Bytes { + // fast path + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err == nil { + *z = v + return z + } + } + + // slow path. // get a big int from our pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() vv.SetBytes(e) // set big int z.SetBigInt(vv) // put temporary object back in pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) return z } -// SetBigInt sets z to v (regular form) and returns z in Montgomery form +// SetBytesCanonical interprets e as the bytes of a big-endian 32-byte integer. +// If e is not a 32-byte slice or encodes a value higher than q, +// SetBytesCanonical returns an error. +func (z *Element) SetBytesCanonical(e []byte) error { + if len(e) != Bytes { + return errors.New("invalid fr.Element encoding") + } + v, err := BigEndian.Element((*[Bytes]byte)(e)) + if err != nil { + return err + } + *z = v + return nil +} + +// SetBigInt sets z to v and returns z func (z *Element) SetBigInt(v *big.Int) *Element { z.SetZero() @@ -849,17 +965,16 @@ func (z *Element) SetBigInt(v *big.Int) *Element { } // get temporary big int from the pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() // copy input + modular reduction - vv.Set(v) vv.Mod(v, &_modulus) // set big int byte value z.setBigInt(vv) // release object into pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) return z } @@ -881,39 +996,40 @@ func (z *Element) setBigInt(v *big.Int) *Element { } } - return z.ToMont() + return z.toMont() } // SetString creates a big.Int with number and calls SetBigInt on z // // The number prefix determines the actual base: A prefix of -// ''0b'' or ''0B'' selects base 2, ''0'', ''0o'' or ''0O'' selects base 8, -// and ''0x'' or ''0X'' selects base 16. Otherwise, the selected base is 10 +// ”0b” or ”0B” selects base 2, ”0”, ”0o” or ”0O” selects base 8, +// and ”0x” or ”0X” selects base 16. Otherwise, the selected base is 10 // and no prefix is accepted. // // For base 16, lower and upper case letters are considered the same: // The letters 'a' to 'f' and 'A' to 'F' represent digit values 10 to 15. // -// An underscore character ''_'' may appear between a base +// An underscore character ”_” may appear between a base // prefix and an adjacent digit, and between successive digits; such // underscores do not change the value of the number. // Incorrect placement of underscores is reported as a panic if there // are no other errors. // -func (z *Element) SetString(number string) *Element { +// If the number is invalid this method leaves z unchanged and returns nil, error. +func (z *Element) SetString(number string) (*Element, error) { // get temporary big int from the pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() if _, ok := vv.SetString(number, 0); !ok { - panic("Element.SetString failed -> can't parse number into a big.Int " + number) + return nil, errors.New("Element.SetString failed -> can't parse number into a big.Int " + number) } z.SetBigInt(vv) // release object into pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) - return z + return z, nil } // MarshalJSON returns json encoding of z (z.Text(10)) @@ -951,7 +1067,7 @@ func (z *Element) UnmarshalJSON(data []byte) error { } // get temporary big int from the pool - vv := bigIntPool.Get().(*big.Int) + vv := pool.BigInt.Get() if _, ok := vv.SetString(s, 0); !ok { return errors.New("can't parse into a big.Int: " + s) @@ -960,10 +1076,79 @@ func (z *Element) UnmarshalJSON(data []byte) error { z.SetBigInt(vv) // release object into pool - bigIntPool.Put(vv) + pool.BigInt.Put(vv) return nil } +// A ByteOrder specifies how to convert byte slices into a Element +type ByteOrder interface { + Element(*[Bytes]byte) (Element, error) + PutElement(*[Bytes]byte, Element) + String() string +} + +// BigEndian is the big-endian implementation of ByteOrder and AppendByteOrder. +var BigEndian bigEndian + +type bigEndian struct{} + +// Element interpret b is a big-endian 32-byte slice. +// If b encodes a value higher than q, Element returns error. +func (bigEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.BigEndian.Uint64((*b)[24:32]) + z[1] = binary.BigEndian.Uint64((*b)[16:24]) + z[2] = binary.BigEndian.Uint64((*b)[8:16]) + z[3] = binary.BigEndian.Uint64((*b)[0:8]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fr.Element encoding") + } + + z.toMont() + return z, nil +} + +func (bigEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.BigEndian.PutUint64((*b)[24:32], e[0]) + binary.BigEndian.PutUint64((*b)[16:24], e[1]) + binary.BigEndian.PutUint64((*b)[8:16], e[2]) + binary.BigEndian.PutUint64((*b)[0:8], e[3]) +} + +func (bigEndian) String() string { return "BigEndian" } + +// LittleEndian is the little-endian implementation of ByteOrder and AppendByteOrder. +var LittleEndian littleEndian + +type littleEndian struct{} + +func (littleEndian) Element(b *[Bytes]byte) (Element, error) { + var z Element + z[0] = binary.LittleEndian.Uint64((*b)[0:8]) + z[1] = binary.LittleEndian.Uint64((*b)[8:16]) + z[2] = binary.LittleEndian.Uint64((*b)[16:24]) + z[3] = binary.LittleEndian.Uint64((*b)[24:32]) + + if !z.smallerThanModulus() { + return Element{}, errors.New("invalid fr.Element encoding") + } + + z.toMont() + return z, nil +} + +func (littleEndian) PutElement(b *[Bytes]byte, e Element) { + e.fromMont() + binary.LittleEndian.PutUint64((*b)[0:8], e[0]) + binary.LittleEndian.PutUint64((*b)[8:16], e[1]) + binary.LittleEndian.PutUint64((*b)[16:24], e[2]) + binary.LittleEndian.PutUint64((*b)[24:32], e[3]) +} + +func (littleEndian) String() string { return "LittleEndian" } + // Legendre returns the Legendre symbol of z (either +1, -1, or 0.) func (z *Element) Legendre() int { var l Element @@ -975,13 +1160,13 @@ func (z *Element) Legendre() int { } // if l == 1 - if (l[3] == 1011752739694698287) && (l[2] == 7381016538464732718) && (l[1] == 3962172157175319849) && (l[0] == 12436184717236109307) { + if l.IsOne() { return 1 } return -1 } -// Sqrt z = √x mod q +// Sqrt z = √x (mod q) // if the square root doesn't exist (x is not a square mod q) // Sqrt leaves z unchanged and returns nil func (z *Element) Sqrt(x *Element) *Element { @@ -996,7 +1181,7 @@ func (z *Element) Sqrt(x *Element) *Element { // y = x^((s+1)/2)) = w * x y.Mul(x, &w) - // b = x^s = w * w * x = y * x + // b = xˢ = w * w * x = y * x b.Mul(&w, &y) // g = nonResidue ^ s @@ -1009,7 +1194,7 @@ func (z *Element) Sqrt(x *Element) *Element { r := uint64(28) // compute legendre symbol - // t = x^((q-1)/2) = r-1 squaring of x^s + // t = x^((q-1)/2) = r-1 squaring of xˢ t = b for i := uint64(0); i < r-1; i++ { t.Square(&t) @@ -1017,7 +1202,7 @@ func (z *Element) Sqrt(x *Element) *Element { if t.IsZero() { return z.SetZero() } - if !((t[3] == 1011752739694698287) && (t[2] == 7381016538464732718) && (t[1] == 3962172157175319849) && (t[0] == 12436184717236109307)) { + if !t.IsOne() { // t != 1, we don't have a square root return nil } @@ -1026,7 +1211,7 @@ func (z *Element) Sqrt(x *Element) *Element { t = b // for t != 1 - for !((t[3] == 1011752739694698287) && (t[2] == 7381016538464732718) && (t[1] == 3962172157175319849) && (t[0] == 12436184717236109307)) { + for !t.IsOne() { t.Square(&t) m++ } @@ -1034,7 +1219,7 @@ func (z *Element) Sqrt(x *Element) *Element { if m == 0 { return z.Set(&y) } - // t = g^(2^(r-m-1)) mod q + // t = g^(2^(r-m-1)) (mod q) ge := int(r - m - 1) t = g for ge > 0 { @@ -1049,64 +1234,40 @@ func (z *Element) Sqrt(x *Element) *Element { } } -func max(a int, b int) int { - if a > b { - return a - } - return b -} - -func min(a int, b int) int { - if a < b { - return a - } - return b -} - -const updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) -const updateFactorIdentityMatrixRow0 = 1 -const updateFactorIdentityMatrixRow1 = 1 << 32 - -func updateFactorsDecompose(c int64) (int64, int64) { - c += updateFactorsConversionBias - const low32BitsFilter int64 = 0xFFFFFFFF - f := c&low32BitsFilter - 0x7FFFFFFF - g := c>>32&low32BitsFilter - 0x7FFFFFFF - return f, g -} - -const k = 32 // word size / 2 -const signBitSelector = uint64(1) << 63 -const approxLowBitsN = k - 1 -const approxHighBitsN = k + 1 -const inversionCorrectionFactorWord0 = 13488105295233737379 -const inversionCorrectionFactorWord1 = 17373395488625725466 -const inversionCorrectionFactorWord2 = 6831692495576925776 -const inversionCorrectionFactorWord3 = 3282329835997625403 +const ( + k = 32 // word size / 2 + signBitSelector = uint64(1) << 63 + approxLowBitsN = k - 1 + approxHighBitsN = k + 1 +) -const invIterationsN = 18 +const ( + inversionCorrectionFactorWord0 = 13488105295233737379 + inversionCorrectionFactorWord1 = 17373395488625725466 + inversionCorrectionFactorWord2 = 6831692495576925776 + inversionCorrectionFactorWord3 = 3282329835997625403 + invIterationsN = 18 +) -// Inverse z = x⁻¹ mod q -// Implements "Optimized Binary GCD for Modular Inversion" -// https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf +// Inverse z = x⁻¹ (mod q) +// +// if x == 0, sets and returns z = x func (z *Element) Inverse(x *Element) *Element { - if x.IsZero() { - z.SetZero() - return z - } + // Implements "Optimized Binary GCD for Modular Inversion" + // https://github.com/pornin/bingcd/blob/main/doc/bingcd.pdf a := *x b := Element{ - qElementWord0, - qElementWord1, - qElementWord2, - qElementWord3, + q0, + q1, + q2, + q3, } // b := q u := Element{1} - // Update factors: we get [u; v]:= [f0 g0; f1 g1] [u; v] - // c_i = f_i + 2³¹ - 1 + 2³² * (g_i + 2³¹ - 1) + // Update factors: we get [u; v] ← [f₀ g₀; f₁ g₁] [u; v] + // cᵢ = fᵢ + 2³¹ - 1 + 2³² * (gᵢ + 2³¹ - 1) var c0, c1 int64 // Saved update factors to reduce the number of field multiplications @@ -1123,12 +1284,14 @@ func (z *Element) Inverse(x *Element) *Element { n := max(a.BitLen(), b.BitLen()) aApprox, bApprox := approximate(&a, n), approximate(&b, n) - // After 0 iterations, we have f₀ ≤ 2⁰ and f₁ < 2⁰ - // f0, g0, f1, g1 = 1, 0, 0, 1 + // f₀, g₀, f₁, g₁ = 1, 0, 0, 1 c0, c1 = updateFactorIdentityMatrixRow0, updateFactorIdentityMatrixRow1 for j := 0; j < approxLowBitsN; j++ { + // -2ʲ < f₀, f₁ ≤ 2ʲ + // |f₀| + |f₁| < 2ʲ⁺¹ + if aApprox&1 == 0 { aApprox /= 2 } else { @@ -1137,17 +1300,20 @@ func (z *Element) Inverse(x *Element) *Element { s = bApprox - aApprox bApprox = aApprox c0, c1 = c1, c0 + // invariants unchanged } aApprox = s / 2 c0 = c0 - c1 - // Now |f₀| < 2ʲ + 2ʲ = 2ʲ⁺¹ - // |f₁| ≤ 2ʲ still + // Now |f₀| < 2ʲ⁺¹ ≤ 2ʲ⁺¹ (only the weaker inequality is needed, strictly speaking) + // Started with f₀ > -2ʲ and f₁ ≤ 2ʲ, so f₀ - f₁ > -2ʲ⁺¹ + // Invariants unchanged for f₁ } c1 *= 2 - // |f₁| ≤ 2ʲ⁺¹ + // -2ʲ⁺¹ < f₁ ≤ 2ʲ⁺¹ + // So now |f₀| + |f₁| < 2ʲ⁺² } s = a @@ -1159,7 +1325,7 @@ func (z *Element) Inverse(x *Element) *Element { if aHi&signBitSelector != 0 { // if aHi < 0 c0, g0 = -c0, -g0 - aHi = a.neg(&a, aHi) + aHi = negL(&a, aHi) } // right-shift a by k-1 bits a[0] = (a[0] >> approxLowBitsN) | ((a[1]) << approxHighBitsN) @@ -1174,7 +1340,7 @@ func (z *Element) Inverse(x *Element) *Element { if bHi&signBitSelector != 0 { // if bHi < 0 f1, c1 = -f1, -c1 - bHi = b.neg(&b, bHi) + bHi = negL(&b, bHi) } // right-shift b by k-1 bits b[0] = (b[0] >> approxLowBitsN) | ((b[1]) << approxHighBitsN) @@ -1184,20 +1350,24 @@ func (z *Element) Inverse(x *Element) *Element { if i&1 == 1 { // Combine current update factors with previously stored ones - // [f₀, g₀; f₁, g₁] ← [f₀, g₀; f₁, g₀] [pf₀, pg₀; pf₀, pg₀] - // We have |f₀|, |g₀|, |pf₀|, |pf₁| ≤ 2ᵏ⁻¹, and that |pf_i| < 2ᵏ⁻¹ for i ∈ {0, 1} - // Then for the new value we get |f₀| < 2ᵏ⁻¹ × 2ᵏ⁻¹ + 2ᵏ⁻¹ × 2ᵏ⁻¹ = 2²ᵏ⁻¹ - // Which leaves us with an extra bit for the sign + // [F₀, G₀; F₁, G₁] ← [f₀, g₀; f₁, g₁] [pf₀, pg₀; pf₁, pg₁], with capital letters denoting new combined values + // We get |F₀| = | f₀pf₀ + g₀pf₁ | ≤ |f₀pf₀| + |g₀pf₁| = |f₀| |pf₀| + |g₀| |pf₁| ≤ 2ᵏ⁻¹|pf₀| + 2ᵏ⁻¹|pf₁| + // = 2ᵏ⁻¹ (|pf₀| + |pf₁|) < 2ᵏ⁻¹ 2ᵏ = 2²ᵏ⁻¹ + // So |F₀| < 2²ᵏ⁻¹ meaning it fits in a 2k-bit signed register - // c0 aliases f0, c1 aliases g1 + // c₀ aliases f₀, c₁ aliases g₁ c0, g0, f1, c1 = c0*pf0+g0*pf1, c0*pg0+g0*pg1, f1*pf0+c1*pf1, f1*pg0+c1*pg1 s = u - u.linearCombSosSigned(&u, c0, &v, g0) - v.linearCombSosSigned(&s, f1, &v, c1) + + // 0 ≤ u, v < 2²⁵⁵ + // |F₀|, |G₀| < 2⁶³ + u.linearComb(&u, c0, &v, g0) + // |F₁|, |G₁| < 2⁶³ + v.linearComb(&s, f1, &v, c1) } else { // Save update factors @@ -1205,19 +1375,51 @@ func (z *Element) Inverse(x *Element) *Element { } } - // For every iteration that we miss, v is not being multiplied by 2²ᵏ⁻² - const pSq int64 = 1 << (2 * (k - 1)) - // If the function is constant-time ish, this loop will not run (probably no need to take it out explicitly) + // For every iteration that we miss, v is not being multiplied by 2ᵏ⁻² + const pSq uint64 = 1 << (2 * (k - 1)) + a = Element{pSq} + // If the function is constant-time ish, this loop will not run (no need to take it out explicitly) for ; i < invIterationsN; i += 2 { - v.mulWSigned(&v, pSq) + // could optimize further with mul by word routine or by pre-computing a table since with k=26, + // we would multiply by pSq up to 13times; + // on x86, the assembly routine outperforms generic code for mul by word + // on arm64, we may loose up to ~5% for 6 limbs + v.Mul(&v, &a) } + u.Set(x) // for correctness check + z.Mul(&v, &Element{ inversionCorrectionFactorWord0, inversionCorrectionFactorWord1, inversionCorrectionFactorWord2, inversionCorrectionFactorWord3, }) + + // correctness check + v.Mul(&u, z) + if !v.IsOne() && !u.IsZero() { + return z.inverseExp(u) + } + + return z +} + +// inverseExp computes z = x⁻¹ (mod q) = x**(q-2) (mod q) +func (z *Element) inverseExp(x Element) *Element { + // e == q-2 + e := Modulus() + e.Sub(e, big.NewInt(2)) + + z.Set(&x) + + for i := e.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if e.Bit(i) == 1 { + z.Mul(z, &x) + } + } + return z } @@ -1246,80 +1448,88 @@ func approximate(x *Element, nBits int) uint64 { return lo | mid | hi } -func (z *Element) linearCombSosSigned(x *Element, xC int64, y *Element, yC int64) { +// linearComb z = xC * x + yC * y; +// 0 ≤ x, y < 2²⁵⁴ +// |xC|, |yC| < 2⁶³ +func (z *Element) linearComb(x *Element, xC int64, y *Element, yC int64) { + // | (hi, z) | < 2 * 2⁶³ * 2²⁵⁴ = 2³¹⁸ + // therefore | hi | < 2⁶² ≤ 2⁶³ hi := z.linearCombNonModular(x, xC, y, yC) z.montReduceSigned(z, hi) } -// montReduceSigned SOS algorithm; xHi must be at most 63 bits long. Last bit of xHi may be used as a sign bit +// montReduceSigned z = (xHi * r + x) * r⁻¹ using the SOS algorithm +// Requires |xHi| < 2⁶³. Most significant bit of xHi is the sign bit. func (z *Element) montReduceSigned(x *Element, xHi uint64) { - const signBitRemover = ^signBitSelector - neg := xHi&signBitSelector != 0 + mustNeg := xHi&signBitSelector != 0 // the SOS implementation requires that most significant bit is 0 // Let X be xHi*r + x - // note that if X is negative we would have initially stored it as 2⁶⁴ r + X + // If X is negative we would have initially stored it as 2⁶⁴ r + X (à la 2's complement) xHi &= signBitRemover // with this a negative X is now represented as 2⁶³ r + X var t [2*Limbs - 1]uint64 var C uint64 - m := x[0] * qInvNegLsw + m := x[0] * qInvNeg - C = madd0(m, qElementWord0, x[0]) - C, t[1] = madd2(m, qElementWord1, x[1], C) - C, t[2] = madd2(m, qElementWord2, x[2], C) - C, t[3] = madd2(m, qElementWord3, x[3], C) + C = madd0(m, q0, x[0]) + C, t[1] = madd2(m, q1, x[1], C) + C, t[2] = madd2(m, q2, x[2], C) + C, t[3] = madd2(m, q3, x[3], C) - // the high word of m * qElement[3] is at most 62 bits - // x[3] + C is at most 65 bits (high word at most 1 bit) - // Thus the resulting C will be at most 63 bits + // m * qElement[3] ≤ (2⁶⁴ - 1) * (2⁶³ - 1) = 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + // x[3] + C ≤ 2*(2⁶⁴ - 1) = 2⁶⁵ - 2 + // On LHS, (C, t[3]) ≤ 2¹²⁷ - 2⁶⁴ - 2⁶³ + 1 + 2⁶⁵ - 2 = 2¹²⁷ + 2⁶³ - 1 + // So on LHS, C ≤ 2⁶³ t[4] = xHi + C - // xHi and C are 63 bits, therefore no overflow + // xHi + C < 2⁶³ + 2⁶³ = 2⁶⁴ + // { const i = 1 - m = t[i] * qInvNegLsw + m = t[i] * qInvNeg - C = madd0(m, qElementWord0, t[i+0]) - C, t[i+1] = madd2(m, qElementWord1, t[i+1], C) - C, t[i+2] = madd2(m, qElementWord2, t[i+2], C) - C, t[i+3] = madd2(m, qElementWord3, t[i+3], C) + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) t[i+Limbs] += C } { const i = 2 - m = t[i] * qInvNegLsw + m = t[i] * qInvNeg - C = madd0(m, qElementWord0, t[i+0]) - C, t[i+1] = madd2(m, qElementWord1, t[i+1], C) - C, t[i+2] = madd2(m, qElementWord2, t[i+2], C) - C, t[i+3] = madd2(m, qElementWord3, t[i+3], C) + C = madd0(m, q0, t[i+0]) + C, t[i+1] = madd2(m, q1, t[i+1], C) + C, t[i+2] = madd2(m, q2, t[i+2], C) + C, t[i+3] = madd2(m, q3, t[i+3], C) t[i+Limbs] += C } { const i = 3 - m := t[i] * qInvNegLsw + m := t[i] * qInvNeg - C = madd0(m, qElementWord0, t[i+0]) - C, z[0] = madd2(m, qElementWord1, t[i+1], C) - C, z[1] = madd2(m, qElementWord2, t[i+2], C) - z[3], z[2] = madd2(m, qElementWord3, t[i+3], C) + C = madd0(m, q0, t[i+0]) + C, z[0] = madd2(m, q1, t[i+1], C) + C, z[1] = madd2(m, q2, t[i+2], C) + z[3], z[2] = madd2(m, q3, t[i+3], C) } - // if z > q → z -= q - // note: this is NOT constant time - if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) { + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { var b uint64 - z[0], b = bits.Sub64(z[0], 4891460686036598785, 0) - z[1], b = bits.Sub64(z[1], 2896914383306846353, b) - z[2], b = bits.Sub64(z[2], 13281191951274694749, b) - z[3], _ = bits.Sub64(z[3], 3486998266802970665, b) + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) } - if neg { + // + + if mustNeg { // We have computed ( 2⁶³ r + X ) r⁻¹ = 2⁶³ + X r⁻¹ instead var b uint64 z[0], b = bits.Sub64(z[0], signBitSelector, 0) @@ -1328,45 +1538,51 @@ func (z *Element) montReduceSigned(x *Element, xHi uint64) { z[3], b = bits.Sub64(z[3], 0, b) // Occurs iff x == 0 && xHi < 0, i.e. X = rX' for -2⁶³ ≤ X' < 0 + if b != 0 { // z[3] = -1 // negative: add q const neg1 = 0xFFFFFFFFFFFFFFFF - b = 0 - z[0], b = bits.Add64(z[0], qElementWord0, b) - z[1], b = bits.Add64(z[1], qElementWord1, b) - z[2], b = bits.Add64(z[2], qElementWord2, b) - z[3], _ = bits.Add64(neg1, qElementWord3, b) + var carry uint64 + + z[0], carry = bits.Add64(z[0], q0, 0) + z[1], carry = bits.Add64(z[1], q1, carry) + z[2], carry = bits.Add64(z[2], q2, carry) + z[3], _ = bits.Add64(neg1, q3, carry) } } } -// mulWSigned mul word signed (w/ montgomery reduction) -func (z *Element) mulWSigned(x *Element, y int64) { - m := y >> 63 - _mulWGeneric(z, x, uint64((y^m)-m)) - // multiply by abs(y) - if y < 0 { - z.Neg(z) - } +const ( + updateFactorsConversionBias int64 = 0x7fffffff7fffffff // (2³¹ - 1)(2³² + 1) + updateFactorIdentityMatrixRow0 = 1 + updateFactorIdentityMatrixRow1 = 1 << 32 +) + +func updateFactorsDecompose(c int64) (int64, int64) { + c += updateFactorsConversionBias + const low32BitsFilter int64 = 0xFFFFFFFF + f := c&low32BitsFilter - 0x7FFFFFFF + g := c>>32&low32BitsFilter - 0x7FFFFFFF + return f, g } -func (z *Element) neg(x *Element, xHi uint64) uint64 { +// negL negates in place [x | xHi] and return the new most significant word xHi +func negL(x *Element, xHi uint64) uint64 { var b uint64 - z[0], b = bits.Sub64(0, x[0], 0) - z[1], b = bits.Sub64(0, x[1], b) - z[2], b = bits.Sub64(0, x[2], b) - z[3], b = bits.Sub64(0, x[3], b) + x[0], b = bits.Sub64(0, x[0], 0) + x[1], b = bits.Sub64(0, x[1], b) + x[2], b = bits.Sub64(0, x[2], b) + x[3], b = bits.Sub64(0, x[3], b) xHi, _ = bits.Sub64(0, xHi, b) return xHi } -// regular multiplication by one word regular (non montgomery) -// Fewer additions than the branch-free for positive y. Could be faster on some architectures -func (z *Element) mulWRegular(x *Element, y int64) uint64 { +// mulWNonModular multiplies by one word in non-montgomery, without reducing +func (z *Element) mulWNonModular(x *Element, y int64) uint64 { // w := abs(y) m := y >> 63 @@ -1379,83 +1595,21 @@ func (z *Element) mulWRegular(x *Element, y int64) uint64 { c, z[3] = madd1(x[3], w, c) if y < 0 { - c = z.neg(z, c) + c = negL(z, c) } return c } -/* -Removed: seems slower -// mulWRegular branch-free regular multiplication by one word (non montgomery) -func (z *Element) mulWRegularBf(x *Element, y int64) uint64 { - - w := uint64(y) - allNeg := uint64(y >> 63) // -1 if y < 0, 0 o.w - - // s[0], s[1] so results are not stored immediately in z. - // x[i] will be needed in the i+1 th iteration. We don't want to overwrite it in case x = z - var s [2]uint64 - var h [2]uint64 - - h[0], s[0] = bits.Mul64(x[0], w) - - c := uint64(0) - b := uint64(0) - - { - const curI = 1 % 2 - const prevI = 1 - curI - const iMinusOne = 1 - 1 - - h[curI], s[curI] = bits.Mul64(x[1], w) - s[curI], c = bits.Add64(s[curI], h[prevI], c) - s[curI], b = bits.Sub64(s[curI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - } - - { - const curI = 2 % 2 - const prevI = 1 - curI - const iMinusOne = 2 - 1 - - h[curI], s[curI] = bits.Mul64(x[2], w) - s[curI], c = bits.Add64(s[curI], h[prevI], c) - s[curI], b = bits.Sub64(s[curI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - } - - { - const curI = 3 % 2 - const prevI = 1 - curI - const iMinusOne = 3 - 1 - - h[curI], s[curI] = bits.Mul64(x[3], w) - s[curI], c = bits.Add64(s[curI], h[prevI], c) - s[curI], b = bits.Sub64(s[curI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - } - { - const curI = 4 % 2 - const prevI = 1 - curI - const iMinusOne = 3 - - s[curI], _ = bits.Sub64(h[prevI], allNeg & x[iMinusOne], b) - z[iMinusOne] = s[prevI] - - return s[curI] + c - } -}*/ - -// Requires NoCarry +// linearCombNonModular computes a linear combination without modular reduction func (z *Element) linearCombNonModular(x *Element, xC int64, y *Element, yC int64) uint64 { var yTimes Element - yHi := yTimes.mulWRegular(y, yC) - xHi := z.mulWRegular(x, xC) + yHi := yTimes.mulWNonModular(y, yC) + xHi := z.mulWNonModular(x, xC) - carry := uint64(0) - z[0], carry = bits.Add64(z[0], yTimes[0], carry) + var carry uint64 + z[0], carry = bits.Add64(z[0], yTimes[0], 0) z[1], carry = bits.Add64(z[1], yTimes[1], carry) z[2], carry = bits.Add64(z[2], yTimes[2], carry) z[3], carry = bits.Add64(z[3], yTimes[3], carry) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_fuzz.go deleted file mode 100644 index a4c87eb250f..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_fuzz.go +++ /dev/null @@ -1,136 +0,0 @@ -//go:build gofuzz -// +build gofuzz - -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fr - -import ( - "bytes" - "encoding/binary" - "io" - "math/big" - "math/bits" -) - -const ( - fuzzInteresting = 1 - fuzzNormal = 0 - fuzzDiscard = -1 -) - -// Fuzz arithmetic operations fuzzer -func Fuzz(data []byte) int { - r := bytes.NewReader(data) - - var e1, e2 Element - e1.SetRawBytes(r) - e2.SetRawBytes(r) - - { - // mul assembly - - var c, _c Element - a, _a, b, _b := e1, e1, e2, e2 - c.Mul(&a, &b) - _mulGeneric(&_c, &_a, &_b) - - if !c.Equal(&_c) { - panic("mul asm != mul generic on Element") - } - } - - { - // inverse - inv := e1 - inv.Inverse(&inv) - - var bInv, b1, b2 big.Int - e1.ToBigIntRegular(&b1) - bInv.ModInverse(&b1, Modulus()) - inv.ToBigIntRegular(&b2) - - if b2.Cmp(&bInv) != 0 { - panic("inverse operation doesn't match big int result") - } - } - - { - // a + -a == 0 - a, b := e1, e1 - b.Neg(&b) - a.Add(&a, &b) - if !a.IsZero() { - panic("a + -a != 0") - } - } - - return fuzzNormal - -} - -// SetRawBytes reads up to Bytes (bytes needed to represent Element) from reader -// and interpret it as big endian uint64 -// used for fuzzing purposes only -func (z *Element) SetRawBytes(r io.Reader) { - - buf := make([]byte, 8) - - for i := 0; i < len(z); i++ { - if _, err := io.ReadFull(r, buf); err != nil { - goto eof - } - z[i] = binary.BigEndian.Uint64(buf[:]) - } -eof: - z[3] %= qElement[3] - - if z.BiggerModulus() { - var b uint64 - z[0], b = bits.Sub64(z[0], qElement[0], 0) - z[1], b = bits.Sub64(z[1], qElement[1], b) - z[2], b = bits.Sub64(z[2], qElement[2], b) - z[3], b = bits.Sub64(z[3], qElement[3], b) - } - - return -} - -func (z *Element) BiggerModulus() bool { - if z[3] > qElement[3] { - return true - } - if z[3] < qElement[3] { - return false - } - - if z[2] > qElement[2] { - return true - } - if z[2] < qElement[2] { - return false - } - - if z[1] > qElement[1] { - return true - } - if z[1] < qElement[1] { - return false - } - - return z[0] >= qElement[0] -} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_mul_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_mul_amd64.s index 764b9c43285..b51bc69986b 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_mul_amd64.s +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_mul_amd64.s @@ -1,4 +1,4 @@ -// +build !amd64_adx +// +build !purego // Copyright 2020 ConsenSys Software Inc. // @@ -45,8 +45,7 @@ GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 // mul(res, x, y *Element) TEXT ·mul(SB), $24-24 - // the algorithm is described here - // https://hackmd.io/@gnark/modular_multiplication + // the algorithm is described in the Element.Mul declaration (.go) // however, to benefit from the ADCX and ADOX carry chains // we split the inner loops in 2: // for i=0 to N-1 diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.go index 78022b3e6f7..e40a9caed55 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.go @@ -1,3 +1,6 @@ +//go:build !purego +// +build !purego + // Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,18 +28,6 @@ func MulBy5(x *Element) //go:noescape func MulBy13(x *Element) -//go:noescape -func add(res, x, y *Element) - -//go:noescape -func sub(res, x, y *Element) - -//go:noescape -func neg(res, x *Element) - -//go:noescape -func double(res, x *Element) - //go:noescape func mul(res, x, y *Element) @@ -46,5 +37,71 @@ func fromMont(res *Element) //go:noescape func reduce(res *Element) +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +// //go:noescape func Butterfly(a, b *Element) + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + mul(z, x, y) + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for doc. + mul(z, x, x) + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.s index d5dca83d259..b9d8a5bfa22 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.s +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_amd64.s @@ -1,3 +1,5 @@ +// +build !purego + // Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -40,118 +42,6 @@ GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 CMOVQCS rb2, ra2; \ CMOVQCS rb3, ra3; \ -// add(res, x, y *Element) -TEXT ·add(SB), NOSPLIT, $0-24 - MOVQ x+8(FP), AX - MOVQ 0(AX), CX - MOVQ 8(AX), BX - MOVQ 16(AX), SI - MOVQ 24(AX), DI - MOVQ y+16(FP), DX - ADDQ 0(DX), CX - ADCQ 8(DX), BX - ADCQ 16(DX), SI - ADCQ 24(DX), DI - - // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) - REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) - - MOVQ res+0(FP), R12 - MOVQ CX, 0(R12) - MOVQ BX, 8(R12) - MOVQ SI, 16(R12) - MOVQ DI, 24(R12) - RET - -// sub(res, x, y *Element) -TEXT ·sub(SB), NOSPLIT, $0-24 - XORQ DI, DI - MOVQ x+8(FP), SI - MOVQ 0(SI), AX - MOVQ 8(SI), DX - MOVQ 16(SI), CX - MOVQ 24(SI), BX - MOVQ y+16(FP), SI - SUBQ 0(SI), AX - SBBQ 8(SI), DX - SBBQ 16(SI), CX - SBBQ 24(SI), BX - MOVQ $0x43e1f593f0000001, R8 - MOVQ $0x2833e84879b97091, R9 - MOVQ $0xb85045b68181585d, R10 - MOVQ $0x30644e72e131a029, R11 - CMOVQCC DI, R8 - CMOVQCC DI, R9 - CMOVQCC DI, R10 - CMOVQCC DI, R11 - ADDQ R8, AX - ADCQ R9, DX - ADCQ R10, CX - ADCQ R11, BX - MOVQ res+0(FP), R12 - MOVQ AX, 0(R12) - MOVQ DX, 8(R12) - MOVQ CX, 16(R12) - MOVQ BX, 24(R12) - RET - -// double(res, x *Element) -TEXT ·double(SB), NOSPLIT, $0-16 - MOVQ x+8(FP), AX - MOVQ 0(AX), DX - MOVQ 8(AX), CX - MOVQ 16(AX), BX - MOVQ 24(AX), SI - ADDQ DX, DX - ADCQ CX, CX - ADCQ BX, BX - ADCQ SI, SI - - // reduce element(DX,CX,BX,SI) using temp registers (DI,R8,R9,R10) - REDUCE(DX,CX,BX,SI,DI,R8,R9,R10) - - MOVQ res+0(FP), R11 - MOVQ DX, 0(R11) - MOVQ CX, 8(R11) - MOVQ BX, 16(R11) - MOVQ SI, 24(R11) - RET - -// neg(res, x *Element) -TEXT ·neg(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DI - MOVQ x+8(FP), AX - MOVQ 0(AX), DX - MOVQ 8(AX), CX - MOVQ 16(AX), BX - MOVQ 24(AX), SI - MOVQ DX, AX - ORQ CX, AX - ORQ BX, AX - ORQ SI, AX - TESTQ AX, AX - JEQ l1 - MOVQ $0x43e1f593f0000001, R8 - SUBQ DX, R8 - MOVQ R8, 0(DI) - MOVQ $0x2833e84879b97091, R8 - SBBQ CX, R8 - MOVQ R8, 8(DI) - MOVQ $0xb85045b68181585d, R8 - SBBQ BX, R8 - MOVQ R8, 16(DI) - MOVQ $0x30644e72e131a029, R8 - SBBQ SI, R8 - MOVQ R8, 24(DI) - RET - -l1: - MOVQ AX, 0(DI) - MOVQ AX, 8(DI) - MOVQ AX, 16(DI) - MOVQ AX, 24(DI) - RET - TEXT ·reduce(SB), NOSPLIT, $0-8 MOVQ res+0(FP), AX MOVQ 0(AX), DX diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_noasm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_noasm.go deleted file mode 100644 index ec1fac18d63..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_noasm.go +++ /dev/null @@ -1,78 +0,0 @@ -//go:build !amd64 -// +build !amd64 - -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package fr - -// /!\ WARNING /!\ -// this code has not been audited and is provided as-is. In particular, -// there is no security guarantees such as constant time implementation -// or side-channel attack resistance -// /!\ WARNING /!\ - -// MulBy3 x *= 3 -func MulBy3(x *Element) { - mulByConstant(x, 3) -} - -// MulBy5 x *= 5 -func MulBy5(x *Element) { - mulByConstant(x, 5) -} - -// MulBy13 x *= 13 -func MulBy13(x *Element) { - mulByConstant(x, 13) -} - -// Butterfly sets -// a = a + b -// b = a - b -func Butterfly(a, b *Element) { - _butterflyGeneric(a, b) -} - -func mul(z, x, y *Element) { - _mulGeneric(z, x, y) -} - -// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation -// sets and returns z = z * 1 -func fromMont(z *Element) { - _fromMontGeneric(z) -} - -func add(z, x, y *Element) { - _addGeneric(z, x, y) -} - -func double(z, x *Element) { - _doubleGeneric(z, x) -} - -func sub(z, x, y *Element) { - _subGeneric(z, x, y) -} - -func neg(z, x *Element) { - _negGeneric(z, x) -} - -func reduce(z *Element) { - _reduceGeneric(z) -} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_purego.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_purego.go new file mode 100644 index 00000000000..be0f0858326 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element_ops_purego.go @@ -0,0 +1,443 @@ +//go:build !amd64 || purego +// +build !amd64 purego + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import "math/bits" + +// MulBy3 x *= 3 (mod q) +func MulBy3(x *Element) { + _x := *x + x.Double(x).Add(x, &_x) +} + +// MulBy5 x *= 5 (mod q) +func MulBy5(x *Element) { + _x := *x + x.Double(x).Double(x).Add(x, &_x) +} + +// MulBy13 x *= 13 (mod q) +func MulBy13(x *Element) { + var y = Element{ + 17868810749992763324, + 5924006745939515753, + 769406925088786241, + 2691790815622165739, + } + x.Mul(x, &y) +} + +// Butterfly sets +// +// a = a + b (mod q) +// b = a - b (mod q) +func Butterfly(a, b *Element) { + _butterflyGeneric(a, b) +} + +func fromMont(z *Element) { + _fromMontGeneric(z) +} + +func reduce(z *Element) { + _reduceGeneric(z) +} + +// Mul z = x * y (mod q) +// +// x and y must be less than q +func (z *Element) Mul(x, y *Element) *Element { + + // Implements CIOS multiplication -- section 2.3.2 of Tolga Acar's thesis + // https://www.microsoft.com/en-us/research/wp-content/uploads/1998/06/97Acar.pdf + // + // The algorithm: + // + // for i=0 to N-1 + // C := 0 + // for j=0 to N-1 + // (C,t[j]) := t[j] + x[j]*y[i] + C + // (t[N+1],t[N]) := t[N] + C + // + // C := 0 + // m := t[0]*q'[0] mod D + // (C,_) := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // (C,t[N-1]) := t[N] + C + // t[N] := t[N+1] + C + // + // → N is the number of machine words needed to store the modulus q + // → D is the word size. For example, on a 64-bit architecture D is 2 64 + // → x[i], y[i], q[i] is the ith word of the numbers x,y,q + // → q'[0] is the lowest word of the number -q⁻¹ mod r. This quantity is pre-computed, as it does not depend on the inputs. + // → t is a temporary array of size N+2 + // → C, S are machine words. A pair (C,S) refers to (hi-bits, lo-bits) of a two-word number + // + // As described here https://hackmd.io/@gnark/modular_multiplication we can get rid of one carry chain and simplify: + // (also described in https://eprint.iacr.org/2022/1400.pdf annex) + // + // for i=0 to N-1 + // (A,t[0]) := t[0] + x[0]*y[i] + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // (C,t[j-1]) := t[j] + m*q[j] + C + // + // t[N-1] = C + A + // + // This optimization saves 5N + 2 additions in the algorithm, and can be used whenever the highest bit + // of the modulus is zero (and not all of the remaining bits are set). + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, y[0]) + u1, t1 = bits.Mul64(v, y[1]) + u2, t2 = bits.Mul64(v, y[2]) + u3, t3 = bits.Mul64(v, y[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, y[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, y[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, y[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, y[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} + +// Square z = x * x (mod q) +// +// x must be less than q +func (z *Element) Square(x *Element) *Element { + // see Mul for algorithm documentation + + var t0, t1, t2, t3 uint64 + var u0, u1, u2, u3 uint64 + { + var c0, c1, c2 uint64 + v := x[0] + u0, t0 = bits.Mul64(v, x[0]) + u1, t1 = bits.Mul64(v, x[1]) + u2, t2 = bits.Mul64(v, x[2]) + u3, t3 = bits.Mul64(v, x[3]) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, 0, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[1] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[2] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + { + var c0, c1, c2 uint64 + v := x[3] + u0, c1 = bits.Mul64(v, x[0]) + t0, c0 = bits.Add64(c1, t0, 0) + u1, c1 = bits.Mul64(v, x[1]) + t1, c0 = bits.Add64(c1, t1, c0) + u2, c1 = bits.Mul64(v, x[2]) + t2, c0 = bits.Add64(c1, t2, c0) + u3, c1 = bits.Mul64(v, x[3]) + t3, c0 = bits.Add64(c1, t3, c0) + + c2, _ = bits.Add64(0, 0, c0) + t1, c0 = bits.Add64(u0, t1, 0) + t2, c0 = bits.Add64(u1, t2, c0) + t3, c0 = bits.Add64(u2, t3, c0) + c2, _ = bits.Add64(u3, c2, c0) + + m := qInvNeg * t0 + + u0, c1 = bits.Mul64(m, q0) + _, c0 = bits.Add64(t0, c1, 0) + u1, c1 = bits.Mul64(m, q1) + t0, c0 = bits.Add64(t1, c1, c0) + u2, c1 = bits.Mul64(m, q2) + t1, c0 = bits.Add64(t2, c1, c0) + u3, c1 = bits.Mul64(m, q3) + + t2, c0 = bits.Add64(0, c1, c0) + u3, _ = bits.Add64(u3, 0, c0) + t0, c0 = bits.Add64(u0, t0, 0) + t1, c0 = bits.Add64(u1, t1, c0) + t2, c0 = bits.Add64(u2, t2, c0) + c2, _ = bits.Add64(c2, 0, c0) + t2, c0 = bits.Add64(t3, t2, 0) + t3, _ = bits.Add64(u3, c2, c0) + + } + z[0] = t0 + z[1] = t1 + z[2] = t2 + z[3] = t3 + + // if z ⩾ q → z -= q + if !z.smallerThanModulus() { + var b uint64 + z[0], b = bits.Sub64(z[0], q0, 0) + z[1], b = bits.Sub64(z[1], q1, b) + z[2], b = bits.Sub64(z[2], q2, b) + z[3], _ = bits.Sub64(z[3], q3, b) + } + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/mimc.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/mimc.go deleted file mode 100644 index 22492ad185f..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc/mimc.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package mimc - -import ( - "hash" - "math/big" - - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "golang.org/x/crypto/sha3" -) - -const mimcNbRounds = 91 - -// BlockSize size that mimc consumes -const BlockSize = fr.Bytes - -// Params constants for the mimc hash function -type Params []fr.Element - -// NewParams creates new mimc object -func NewParams(seed string) Params { - - // set the constants - res := make(Params, mimcNbRounds) - - rnd := sha3.Sum256([]byte(seed)) - value := new(big.Int).SetBytes(rnd[:]) - - for i := 0; i < mimcNbRounds; i++ { - rnd = sha3.Sum256(value.Bytes()) - value.SetBytes(rnd[:]) - res[i].SetBigInt(value) - } - - return res -} - -// digest represents the partial evaluation of the checksum -// along with the params of the mimc function -type digest struct { - Params Params - h fr.Element - data []byte // data to hash -} - -// NewMiMC returns a MiMCImpl object, pure-go reference implementation -func NewMiMC(seed string) hash.Hash { - d := new(digest) - params := NewParams(seed) - //d.Reset() - d.Params = params - d.Reset() - return d -} - -// Reset resets the Hash to its initial state. -func (d *digest) Reset() { - d.data = nil - d.h = fr.Element{0, 0, 0, 0} -} - -// Sum appends the current hash to b and returns the resulting slice. -// It does not change the underlying hash state. -func (d *digest) Sum(b []byte) []byte { - buffer := d.checksum() - d.data = nil // flush the data already hashed - hash := buffer.Bytes() - b = append(b, hash[:]...) - return b -} - -// BlockSize returns the hash's underlying block size. -// The Write method must be able to accept any amount -// of data, but it may operate more efficiently if all writes -// are a multiple of the block size. -func (d *digest) Size() int { - return BlockSize -} - -// BlockSize returns the number of bytes Sum will return. -func (d *digest) BlockSize() int { - return BlockSize -} - -// Write (via the embedded io.Writer interface) adds more data to the running hash. -// It never returns an error. -func (d *digest) Write(p []byte) (n int, err error) { - n = len(p) - d.data = append(d.data, p...) - return -} - -// Hash hash using Miyaguchi–Preneel: -// https://en.wikipedia.org/wiki/One-way_compression_function -// The XOR operation is replaced by field addition, data is in Montgomery form -func (d *digest) checksum() fr.Element { - - var buffer [BlockSize]byte - var x fr.Element - - // if data size is not multiple of BlockSizes we padd: - // .. || 0xaf8 -> .. || 0x0000...0af8 - if len(d.data)%BlockSize != 0 { - q := len(d.data) / BlockSize - r := len(d.data) % BlockSize - sliceq := make([]byte, q*BlockSize) - copy(sliceq, d.data) - slicer := make([]byte, r) - copy(slicer, d.data[q*BlockSize:]) - sliceremainder := make([]byte, BlockSize-r) - d.data = append(sliceq, sliceremainder...) - d.data = append(d.data, slicer...) - } - - if len(d.data) == 0 { - d.data = make([]byte, 32) - } - - nbChunks := len(d.data) / BlockSize - - for i := 0; i < nbChunks; i++ { - copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) - x.SetBytes(buffer[:]) - d.encrypt(x) - d.h.Add(&x, &d.h) - } - - return d.h -} - -// plain execution of a mimc run -// m: message -// k: encryption key -func (d *digest) encrypt(m fr.Element) { - - for i := 0; i < len(d.Params); i++ { - // m = (m+k+c)^5 - var tmp fr.Element - tmp.Add(&m, &d.h).Add(&tmp, &d.Params[i]) - m.Square(&tmp). - Square(&m). - Mul(&m, &tmp) - } - m.Add(&m, &d.h) - d.h = m -} - -// Sum computes the mimc hash of msg from seed -func Sum(seed string, msg []byte) ([]byte, error) { - params := NewParams(seed) - var d digest - d.Params = params - if _, err := d.Write(msg); err != nil { - return nil, err - } - h := d.checksum() - bytes := h.Bytes() - return bytes[:], nil -} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/vector.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/vector.go new file mode 100644 index 00000000000..00ad8a8986b --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/vector.go @@ -0,0 +1,253 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fr + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "runtime" + "strings" + "sync" + "sync/atomic" + "unsafe" +) + +// Vector represents a slice of Element. +// +// It implements the following interfaces: +// - Stringer +// - io.WriterTo +// - io.ReaderFrom +// - encoding.BinaryMarshaler +// - encoding.BinaryUnmarshaler +// - sort.Interface +type Vector []Element + +// MarshalBinary implements encoding.BinaryMarshaler +func (vector *Vector) MarshalBinary() (data []byte, err error) { + var buf bytes.Buffer + + if _, err = vector.WriteTo(&buf); err != nil { + return + } + return buf.Bytes(), nil +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (vector *Vector) UnmarshalBinary(data []byte) error { + r := bytes.NewReader(data) + _, err := vector.ReadFrom(r) + return err +} + +// WriteTo implements io.WriterTo and writes a vector of big endian encoded Element. +// Length of the vector is encoded as a uint32 on the first 4 bytes. +func (vector *Vector) WriteTo(w io.Writer) (int64, error) { + // encode slice length + if err := binary.Write(w, binary.BigEndian, uint32(len(*vector))); err != nil { + return 0, err + } + + n := int64(4) + + var buf [Bytes]byte + for i := 0; i < len(*vector); i++ { + BigEndian.PutElement(&buf, (*vector)[i]) + m, err := w.Write(buf[:]) + n += int64(m) + if err != nil { + return n, err + } + } + return n, nil +} + +// AsyncReadFrom reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +// It consumes the needed bytes from the reader and returns the number of bytes read and an error if any. +// It also returns a channel that will be closed when the validation is done. +// The validation consist of checking that the elements are smaller than the modulus, and +// converting them to montgomery form. +func (vector *Vector) AsyncReadFrom(r io.Reader) (int64, error, chan error) { + chErr := make(chan error, 1) + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + close(chErr) + return int64(read), err, chErr + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + if sliceLen == 0 { + close(chErr) + return n, nil, chErr + } + + bSlice := unsafe.Slice((*byte)(unsafe.Pointer(&(*vector)[0])), sliceLen*Bytes) + read, err := io.ReadFull(r, bSlice) + n += int64(read) + if err != nil { + close(chErr) + return n, err, chErr + } + + go func() { + var cptErrors uint64 + // process the elements in parallel + execute(int(sliceLen), func(start, end int) { + + var z Element + for i := start; i < end; i++ { + // we have to set vector[i] + bstart := i * Bytes + bend := bstart + Bytes + b := bSlice[bstart:bend] + z[0] = binary.BigEndian.Uint64(b[24:32]) + z[1] = binary.BigEndian.Uint64(b[16:24]) + z[2] = binary.BigEndian.Uint64(b[8:16]) + z[3] = binary.BigEndian.Uint64(b[0:8]) + + if !z.smallerThanModulus() { + atomic.AddUint64(&cptErrors, 1) + return + } + z.toMont() + (*vector)[i] = z + } + }) + + if cptErrors > 0 { + chErr <- fmt.Errorf("async read: %d elements failed validation", cptErrors) + } + close(chErr) + }() + return n, nil, chErr +} + +// ReadFrom implements io.ReaderFrom and reads a vector of big endian encoded Element. +// Length of the vector must be encoded as a uint32 on the first 4 bytes. +func (vector *Vector) ReadFrom(r io.Reader) (int64, error) { + + var buf [Bytes]byte + if read, err := io.ReadFull(r, buf[:4]); err != nil { + return int64(read), err + } + sliceLen := binary.BigEndian.Uint32(buf[:4]) + + n := int64(4) + (*vector) = make(Vector, sliceLen) + + for i := 0; i < int(sliceLen); i++ { + read, err := io.ReadFull(r, buf[:]) + n += int64(read) + if err != nil { + return n, err + } + (*vector)[i], err = BigEndian.Element(&buf) + if err != nil { + return n, err + } + } + + return n, nil +} + +// String implements fmt.Stringer interface +func (vector Vector) String() string { + var sbb strings.Builder + sbb.WriteByte('[') + for i := 0; i < len(vector); i++ { + sbb.WriteString(vector[i].String()) + if i != len(vector)-1 { + sbb.WriteByte(',') + } + } + sbb.WriteByte(']') + return sbb.String() +} + +// Len is the number of elements in the collection. +func (vector Vector) Len() int { + return len(vector) +} + +// Less reports whether the element with +// index i should sort before the element with index j. +func (vector Vector) Less(i, j int) bool { + return vector[i].Cmp(&vector[j]) == -1 +} + +// Swap swaps the elements with indexes i and j. +func (vector Vector) Swap(i, j int) { + vector[i], vector[j] = vector[j], vector[i] +} + +// TODO @gbotrel make a public package out of that. +// execute executes the work function in parallel. +// this is copy paste from internal/parallel/parallel.go +// as we don't want to generate code importing internal/ +func execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + if nbTasks < 1 { + nbTasks = 1 + } else if nbTasks > 512 { + nbTasks = 512 + } + } + + if nbTasks == 1 { + // no go routines + work(0, nbIterations) + return + } + + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fuzz.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fuzz.go deleted file mode 100644 index 69b9c450507..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fuzz.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build gofuzz -// +build gofuzz - -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by consensys/gnark-crypto DO NOT EDIT - -package bn254 - -import ( - "bytes" - "github.com/consensys/gnark-crypto/ecc/bn254/fp" - "github.com/consensys/gnark-crypto/ecc/bn254/fr" - "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" - "math/big" -) - -const ( - fuzzInteresting = 1 - fuzzNormal = 0 - fuzzDiscard = -1 -) - -func Fuzz(data []byte) int { - // TODO separate in multiple FuzzXXX and update continuous fuzzer scripts - // else, we don't really benefits for fuzzer strategy. - fr.Fuzz(data) - fp.Fuzz(data) - mimc.Fuzz(data) - - // fuzz pairing - r := bytes.NewReader(data) - var e1, e2 fr.Element - e1.SetRawBytes(r) - e2.SetRawBytes(r) - - { - var r, r1, r2, r1r2, zero GT - var b1, b2, b1b2 big.Int - e1.ToBigIntRegular(&b1) - e2.ToBigIntRegular(&b2) - b1b2.Mul(&b1, &b2) - - var p1 G1Affine - var p2 G2Affine - - p1.ScalarMultiplication(&g1GenAff, &b1) - p2.ScalarMultiplication(&g2GenAff, &b2) - - r, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{g2GenAff}) - r1, _ = Pair([]G1Affine{p1}, []G2Affine{g2GenAff}) - r2, _ = Pair([]G1Affine{g1GenAff}, []G2Affine{p2}) - - r1r2.Exp(&r, b1b2) - r1.Exp(&r1, b2) - r2.Exp(&r2, b1) - - if !(r1r2.Equal(&r1) && r1r2.Equal(&r2) && !r.Equal(&zero)) { - panic("pairing bilinearity check failed") - } - } - - return fuzzNormal -} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g1.go index 8a5f823d00e..e64b53ffa7a 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g1.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g1.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,14 +17,12 @@ package bn254 import ( - "math" - "math/big" - "runtime" - "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/internal/parallel" + "math/big" + "runtime" ) // G1Affine point in affine coordinates @@ -37,7 +35,7 @@ type G1Jac struct { X, Y, Z fp.Element } -// g1JacExtended parameterized jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ**3=ZZZ**2) +// g1JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g1JacExtended struct { X, Y, ZZ, ZZZ fp.Element } @@ -51,7 +49,14 @@ func (p *G1Affine) Set(a *G1Affine) *G1Affine { return p } -// ScalarMultiplication computes and returns p = a*s +// setInfinity sets p to O +func (p *G1Affine) setInfinity() *G1Affine { + p.X.SetZero() + p.Y.SetZero() + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { var _p G1Jac _p.FromAffine(a) @@ -60,9 +65,24 @@ func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { return p } +// ScalarMultiplicationAffine computes and returns p = a ⋅ s +// Takes an affine point and returns a Jacobian point (useful for KZG) +func (p *G1Jac) ScalarMultiplicationAffine(a *G1Affine, s *big.Int) *G1Jac { + p.FromAffine(a) + p.mulGLV(p, s) + return p +} + +// ScalarMultiplicationBase computes and returns p = g ⋅ s where g is the prime subgroup generator +func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { + var _p G1Jac + _p.mulGLV(&g1Gen, s) + p.FromJacobian(&_p) + return p +} + // Add adds two point in affine coordinates. -// This should rarely be used as it is very inneficient compared to Jacobian -// TODO implement affine addition formula +// This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { var p1, p2 G1Jac p1.FromAffine(a) @@ -72,9 +92,18 @@ func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { return p } +// Double doubles a point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G1Affine) Double(a *G1Affine) *G1Affine { + var p1 G1Jac + p1.FromAffine(a) + p1.Double(&p1) + p.FromJacobian(&p1) + return p +} + // Sub subs two point in affine coordinates. -// This should rarely be used as it is very inneficient compared to Jacobian -// TODO implement affine addition formula +// This should rarely be used as it is very inefficient compared to Jacobian func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { var p1, p2 G1Jac p1.FromAffine(a) @@ -96,7 +125,7 @@ func (p *G1Affine) Neg(a *G1Affine) *G1Affine { return p } -// FromJacobian rescale a point in Jacobian coord in z=1 plane +// FromJacobian rescales a point in Jacobian coord in z=1 plane func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { var a, b fp.Element @@ -115,14 +144,17 @@ func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { return p } +// String returns the string representation of the point or "O" if it is infinity func (p *G1Affine) String() string { - var x, y fp.Element - x.Set(&p.X) - y.Set(&p.Y) - return "E([" + x.String() + "," + y.String() + "])," + if p.IsInfinity() { + return "O" + } + return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity (in affine, it's encoded as (0,0)) +// IsInfinity checks if the point is infinity +// in affine, it's encoded as (0,0) +// (0,0) is never on the curve for j=0 curves func (p *G1Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } @@ -152,17 +184,30 @@ func (p *G1Jac) Set(a *G1Jac) *G1Jac { // Equal tests if two points (in Jacobian coordinates) are equal func (p *G1Jac) Equal(a *G1Jac) bool { - - if p.Z.IsZero() && a.Z.IsZero() { - return true + // If one point is infinity, the other must also be infinity. + if p.Z.IsZero() { + return a.Z.IsZero() } - _p := G1Affine{} - _p.FromJacobian(p) + // If the other point is infinity, return false since we can't + // the following checks would be incorrect. + if a.Z.IsZero() { + return false + } + + var pZSquare, aZSquare fp.Element + pZSquare.Square(&p.Z) + aZSquare.Square(&a.Z) - _a := G1Affine{} - _a.FromJacobian(a) + var lhs, rhs fp.Element + lhs.Mul(&p.X, &aZSquare) + rhs.Mul(&a.X, &pZSquare) + if !lhs.Equal(&rhs) { + return false + } + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) + rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) - return _p.X.Equal(&_a.X) && _p.Y.Equal(&_a.Y) + return lhs.Equal(&rhs) } // Neg computes -G @@ -172,7 +217,7 @@ func (p *G1Jac) Neg(a *G1Jac) *G1Jac { return p } -// SubAssign substracts two points on the curve +// SubAssign subtracts two points on the curve func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { var tmp G1Jac tmp.Set(a) @@ -239,7 +284,7 @@ func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { //if a is infinity return p - if a.X.IsZero() && a.Y.IsZero() { + if a.IsInfinity() { return p } // p is infinity, return a @@ -323,24 +368,22 @@ func (p *G1Jac) DoubleAssign() *G1Jac { return p } -// ScalarMultiplication computes and returns p = a*s +// ScalarMultiplication computes and returns p = a ⋅ s // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { return p.mulGLV(a, s) } +// String returns canonical representation of the point in affine coordinates func (p *G1Jac) String() string { - if p.Z.IsZero() { - return "O" - } _p := G1Affine{} _p.FromJacobian(p) - return "E([" + _p.X.String() + "," + _p.Y.String() + "])," + return _p.String() } -// FromAffine sets p = Q, p in Jacboian, Q in affine +// FromAffine sets p = Q, p in Jacobian, Q in affine func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { - if Q.X.IsZero() && Q.Y.IsZero() { + if Q.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() @@ -367,22 +410,25 @@ func (p *G1Jac) IsOnCurve() bool { } // IsInSubGroup returns true if p is on the r-torsion, false otherwise. -// For bn curves, the r-torsion in E(Fp) is the full group, so we just check that -// the point is on the curve. +// the curve is of prime order i.e. E(𝔽p) is the full group +// so we just check that the point is on the curve. func (p *G1Jac) IsInSubGroup() bool { return p.IsOnCurve() } -// mulWindowed 2-bits windowed exponentiation +// mulWindowed computes a 2-bits windowed scalar multiplication func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { var res G1Jac var ops [3]G1Jac - res.Set(&g1Infinity) ops[0].Set(a) + if s.Sign() == -1 { + ops[0].Neg(&ops[0]) + } + res.Set(&g1Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) @@ -405,14 +451,15 @@ func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { } -// phi assigns p to phi(a) where phi: (x,y)->(ux,y), and returns p +// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p +// where w is a third root of unity in 𝔽p func (p *G1Jac) phi(a *G1Jac) *G1Jac { p.Set(a) p.X.Mul(&p.X, &thirdRootOneG1) return p } -// mulGLV performs scalar multiplication using GLV +// mulGLV computes the scalar multiplication using a windowed-GLV method // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { @@ -422,11 +469,11 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { res.Set(&g1Infinity) - // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a table[0].Set(a) table[3].phi(a) - // split the scalar, modifies +-a, phi(a) accordingly + // split the scalar, modifies ±a, ϕ(a) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -439,7 +486,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -454,12 +501,20 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { table[13].Set(&table[11]).AddAssign(&table[1]) table[14].Set(&table[11]).AddAssign(&table[2]) - // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 bits long max - k1.SetBigInt(&k[0]).FromMont() - k2.SetBigInt(&k[1]).FromMont() + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max + // this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift + k1 = k1.SetBigInt(&k[0]).Bits() + k2 = k2.SetBigInt(&k[1]).Bits() + + // we don't target constant-timeness so we check first if we increase the bounds or not + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 - // loop starts from len(k1)/2 due to the bounds - for i := int(math.Ceil(fr.Limbs/2. - 1)); i >= 0; i-- { + // loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.Double(&res).Double(&res) @@ -477,6 +532,77 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { return p } +// JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique +// where g is the prime subgroup generator +func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { + + var res, p1, p2 G1Jac + res.Set(&g1Infinity) + p1.Set(&g1Gen) + p2.FromAffine(a) + + var table [15]G1Jac + + var k1, k2 big.Int + if s1.Sign() == -1 { + k1.Neg(s1) + table[0].Neg(&p1) + } else { + k1.Set(s1) + table[0].Set(&p1) + } + if s2.Sign() == -1 { + k2.Neg(s2) + table[3].Neg(&p2) + } else { + k2.Set(s2) + table[3].Set(&p2) + } + + // precompute table (2 bits sliding window) + table[1].Double(&table[0]) + table[2].Set(&table[1]).AddAssign(&table[0]) + table[4].Set(&table[3]).AddAssign(&table[0]) + table[5].Set(&table[3]).AddAssign(&table[1]) + table[6].Set(&table[3]).AddAssign(&table[2]) + table[7].Double(&table[3]) + table[8].Set(&table[7]).AddAssign(&table[0]) + table[9].Set(&table[7]).AddAssign(&table[1]) + table[10].Set(&table[7]).AddAssign(&table[2]) + table[11].Set(&table[7]).AddAssign(&table[3]) + table[12].Set(&table[11]).AddAssign(&table[0]) + table[13].Set(&table[11]).AddAssign(&table[1]) + table[14].Set(&table[11]).AddAssign(&table[2]) + + var s [2]fr.Element + s[0] = s[0].SetBigInt(&k1).Bits() + s[1] = s[1].SetBigInt(&k2).Bits() + + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.Double(&res).Double(&res) + b1 := (s[0][i] & mask) >> (62 - 2*j) + b2 := (s[1][i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.AddAssign(&table[s-1]) + } + mask = mask >> 2 + } + } + + p.Set(&res) + return p + +} + // ------------------------------------------------------------------------------------------------- // Jacobian extended @@ -495,7 +621,11 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { return p } -// fromJacExtended sets Q in affine coords +func (p *g1JacExtended) IsZero() bool { + return p.ZZ.IsZero() +} + +// fromJacExtended sets Q in affine coordinates func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { if Q.ZZ.IsZero() { p.X = fp.Element{} @@ -507,7 +637,7 @@ func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { return p } -// fromJacExtended sets Q in Jacobian coords +// fromJacExtended sets Q in Jacobian coordinates func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { if Q.ZZ.IsZero() { p.Set(&g1Infinity) @@ -519,7 +649,7 @@ func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { return p } -// unsafeFromJacExtended sets p in jacobian coords, but don't check for infinity +// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) @@ -527,7 +657,7 @@ func (p *G1Jac) unsafeFromJacExtended(Q *g1JacExtended) *G1Jac { return p } -// add point in ZZ coords +// add point in Jacobian extended coordinates // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { //if q is infinity return p @@ -540,15 +670,15 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } - var A, B, X1ZZ2, X2ZZ1, Y1ZZZ2, Y2ZZZ1 fp.Element + var A, B, U1, U2, S1, S2 fp.Element // p2: q, p1: p - X2ZZ1.Mul(&q.X, &p.ZZ) - X1ZZ2.Mul(&p.X, &q.ZZ) - A.Sub(&X2ZZ1, &X1ZZ2) - Y2ZZZ1.Mul(&q.Y, &p.ZZZ) - Y1ZZZ2.Mul(&p.Y, &q.ZZZ) - B.Sub(&Y2ZZZ1, &Y1ZZZ2) + U2.Mul(&q.X, &p.ZZ) + U1.Mul(&p.X, &q.ZZ) + A.Sub(&U2, &U1) + S2.Mul(&q.Y, &p.ZZZ) + S1.Mul(&p.Y, &q.ZZZ) + B.Sub(&S2, &S1) if A.IsZero() { if B.IsZero() { @@ -560,11 +690,7 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } - var U1, U2, S1, S2, P, R, PP, PPP, Q, V fp.Element - U1.Mul(&p.X, &q.ZZ) - U2.Mul(&q.X, &p.ZZ) - S1.Mul(&p.Y, &q.ZZZ) - S2.Mul(&q.Y, &p.ZZZ) + var P, R, PP, PPP, Q, V fp.Element P.Sub(&U2, &U1) R.Sub(&S2, &S1) PP.Square(&P) @@ -587,8 +713,10 @@ func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { return p } -// double point in ZZ coords +// double point in Jacobian extended coordinates // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +// since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { var U, V, W, S, XX, M fp.Element @@ -618,7 +746,7 @@ func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p - if a.X.IsZero() && a.Y.IsZero() { + if a.IsInfinity() { return p } // p is infinity, return a @@ -674,7 +802,7 @@ func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { //if a is infinity return p - if a.X.IsZero() && a.Y.IsZero() { + if a.IsInfinity() { return p } // p is infinity, return a @@ -751,7 +879,7 @@ func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { return p } -// doubleMixed point in ZZ coords +// doubleMixed point in Jacobian extended coordinates // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { @@ -779,9 +907,9 @@ func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { } // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates -// performing a single field inversion (Montgomery batch inversion trick) -// result must be allocated with len(result) == len(points) -func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { +// performing a single field inversion (Montgomery batch inversion trick). +func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { + result := make([]G1Affine, len(points)) zeroes := make([]bool, len(points)) accumulator := fp.One() @@ -801,7 +929,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { for i := len(points) - 1; i >= 0; i-- { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } result[i].X.Mul(&result[i].X, &accInverse) @@ -812,7 +940,7 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { parallel.Execute(len(points), func(start, end int) { for i := start; i < end; i++ { if zeroes[i] { - // do nothing, X and Y are zeroes in affine. + // do nothing, (X=0, Y=0) is infinity point in affine continue } var a, b fp.Element @@ -824,102 +952,79 @@ func BatchJacobianToAffineG1(points []G1Jac, result []G1Affine) { } }) + return result } -// BatchScalarMultiplicationG1 multiplies the same base (generator) by all scalars +// BatchScalarMultiplicationG1 multiplies the same base by all scalars // and return resulting points in affine coordinates // uses a simple windowed-NAF like exponentiation algorithm func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affine { - // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) nbPoints := uint64(len(scalars)) min := ^uint64(0) bestC := 0 - for c := 2; c < 18; c++ { - cost := uint64(1 << (c - 1)) - nbChunks := uint64(fr.Limbs * 64 / c) - if (fr.Limbs*64)%c != 0 { - nbChunks++ - } - cost += nbPoints * ((fr.Limbs * 64) + nbChunks) + for c := 2; c <= 16; c++ { + cost := uint64(1 << (c - 1)) // pre compute the table + nbChunks := computeNbChunks(uint64(c)) + cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add if cost < min { min = cost bestC = c } } c := uint64(bestC) // window size - nbChunks := int(fr.Limbs * 64 / c) - if (fr.Limbs*64)%c != 0 { - nbChunks++ + nbChunks := int(computeNbChunks(c)) + + // last window may be slightly larger than c; in which case we need to compute one + // extra element in the baseTable + maxC := lastC(c) + if c > maxC { + maxC = c } - mask := uint64((1 << c) - 1) // low c bits are 1 - msbWindow := uint64(1 << (c - 1)) // precompute all powers of base for our window // note here that if performance is critical, we can implement as in the msmX methods // this allocation to be on the stack - baseTable := make([]G1Jac, (1 << (c - 1))) - baseTable[0].Set(&g1Infinity) - baseTable[0].AddMixed(base) + baseTable := make([]G1Jac, (1 << (maxC - 1))) + baseTable[0].FromAffine(base) for i := 1; i < len(baseTable); i++ { baseTable[i] = baseTable[i-1] baseTable[i].AddMixed(base) } - - pScalars, _ := partitionScalars(scalars, c, false, runtime.NumCPU()) - - // compute offset and word selector / shift to select the right bits of our windows - selectors := make([]selector, nbChunks) - for chunk := 0; chunk < nbChunks; chunk++ { - jc := uint64(uint64(chunk) * c) - d := selector{} - d.index = jc / 64 - d.shift = jc - (d.index * 64) - d.mask = mask << d.shift - d.multiWordSelect = (64%c) != 0 && d.shift > (64-c) && d.index < (fr.Limbs-1) - if d.multiWordSelect { - nbBitsHigh := d.shift - uint64(64-c) - d.maskHigh = (1 << nbBitsHigh) - 1 - d.shiftHigh = (c - nbBitsHigh) - } - selectors[chunk] = d - } // convert our base exp table into affine to use AddMixed - baseTableAff := make([]G1Affine, (1 << (c - 1))) - BatchJacobianToAffineG1(baseTable, baseTableAff) + baseTableAff := BatchJacobianToAffineG1(baseTable) toReturn := make([]G1Jac, len(scalars)) - // for each digit, take value in the base table, double it c time, voila. - parallel.Execute(len(pScalars), func(start, end int) { + // partition the scalars into digits + digits, _ := partitionScalars(scalars, c, runtime.NumCPU()) + + // for each digit, take value in the base table, double it c time, voilà. + parallel.Execute(len(scalars), func(start, end int) { var p G1Jac for i := start; i < end; i++ { p.Set(&g1Infinity) for chunk := nbChunks - 1; chunk >= 0; chunk-- { - s := selectors[chunk] if chunk != nbChunks-1 { for j := uint64(0); j < c; j++ { p.DoubleAssign() } } + offset := chunk * len(scalars) + digit := digits[i+offset] - bits := (pScalars[i][s.index] & s.mask) >> s.shift - if s.multiWordSelect { - bits += (pScalars[i][s.index+1] & s.maskHigh) << s.shiftHigh - } - - if bits == 0 { + if digit == 0 { continue } - // if msbWindow bit is set, we need to substract - if bits&msbWindow == 0 { + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { // add - p.AddMixed(&baseTableAff[bits-1]) + p.AddMixed(&baseTableAff[(digit>>1)-1]) } else { // sub - t := baseTableAff[bits & ^msbWindow] + t := baseTableAff[digit>>1] t.Neg(&t) p.AddMixed(&t) } @@ -930,7 +1035,57 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin } }) - toReturnAff := make([]G1Affine, len(scalars)) - BatchJacobianToAffineG1(toReturn, toReturnAff) + toReturnAff := BatchJacobianToAffineG1(toReturn) return toReturnAff } + +// batch add affine coordinates +// using batch inversion +// special cases (doubling, infinity) must be filtered out before this call +func batchAddG1Affine[TP pG1Affine, TPP ppG1Affine, TC cG1Affine](R *TPP, P *TP, batchSize int) { + var lambda, lambdain TC + + // add part + for j := 0; j < batchSize; j++ { + lambdain[j].Sub(&(*P)[j].X, &(*R)[j].X) + } + + // invert denominator using montgomery batch invert technique + { + var accumulator fp.Element + lambda[0].SetOne() + accumulator.Set(&lambdain[0]) + + for i := 1; i < batchSize; i++ { + lambda[i] = accumulator + accumulator.Mul(&accumulator, &lambdain[i]) + } + + accumulator.Inverse(&accumulator) + + for i := batchSize - 1; i > 0; i-- { + lambda[i].Mul(&lambda[i], &accumulator) + accumulator.Mul(&accumulator, &lambdain[i]) + } + lambda[0].Set(&accumulator) + } + + var d fp.Element + var rr G1Affine + + // add part + for j := 0; j < batchSize; j++ { + // computa lambda + d.Sub(&(*P)[j].Y, &(*R)[j].Y) + lambda[j].Mul(&lambda[j], &d) + + // compute X, Y + rr.X.Square(&lambda[j]) + rr.X.Sub(&rr.X, &(*R)[j].X) + rr.X.Sub(&rr.X, &(*P)[j].X) + d.Sub(&(*R)[j].X, &rr.X) + rr.Y.Mul(&lambda[j], &d) + rr.Y.Sub(&rr.Y, &(*R)[j].Y) + (*R)[j].Set(&rr) + } +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g2.go index 6c918b5da62..b4f279fc379 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g2.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g2.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,14 +17,12 @@ package bn254 import ( - "math" - "math/big" - "runtime" - "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" "github.com/consensys/gnark-crypto/internal/parallel" + "math/big" + "runtime" ) // G2Affine point in affine coordinates @@ -37,7 +35,7 @@ type G2Jac struct { X, Y, Z fptower.E2 } -// g2JacExtended parameterized jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ**3=ZZZ**2) +// g2JacExtended parameterized Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) type g2JacExtended struct { X, Y, ZZ, ZZZ fptower.E2 } @@ -56,7 +54,14 @@ func (p *G2Affine) Set(a *G2Affine) *G2Affine { return p } -// ScalarMultiplication computes and returns p = a*s +// setInfinity sets p to O +func (p *G2Affine) setInfinity() *G2Affine { + p.X.SetZero() + p.Y.SetZero() + return p +} + +// ScalarMultiplication computes and returns p = a ⋅ s func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { var _p G2Jac _p.FromAffine(a) @@ -66,8 +71,7 @@ func (p *G2Affine) ScalarMultiplication(a *G2Affine, s *big.Int) *G2Affine { } // Add adds two point in affine coordinates. -// This should rarely be used as it is very inneficient compared to Jacobian -// TODO implement affine addition formula +// This should rarely be used as it is very inefficient compared to Jacobian func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { var p1, p2 G2Jac p1.FromAffine(a) @@ -77,9 +81,18 @@ func (p *G2Affine) Add(a, b *G2Affine) *G2Affine { return p } +// Double doubles a point in affine coordinates. +// This should rarely be used as it is very inefficient compared to Jacobian +func (p *G2Affine) Double(a *G2Affine) *G2Affine { + var p1 G2Jac + p1.FromAffine(a) + p1.Double(&p1) + p.FromJacobian(&p1) + return p +} + // Sub subs two point in affine coordinates. -// This should rarely be used as it is very inneficient compared to Jacobian -// TODO implement affine addition formula +// This should rarely be used as it is very inefficient compared to Jacobian func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { var p1, p2 G2Jac p1.FromAffine(a) @@ -101,7 +114,7 @@ func (p *G2Affine) Neg(a *G2Affine) *G2Affine { return p } -// FromJacobian rescale a point in Jacobian coord in z=1 plane +// FromJacobian rescales a point in Jacobian coord in z=1 plane func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { var a, b fptower.E2 @@ -120,14 +133,17 @@ func (p *G2Affine) FromJacobian(p1 *G2Jac) *G2Affine { return p } +// String returns the string representation of the point or "O" if it is infinity func (p *G2Affine) String() string { - var x, y fptower.E2 - x.Set(&p.X) - y.Set(&p.Y) - return "E([" + x.String() + "," + y.String() + "])," + if p.IsInfinity() { + return "O" + } + return "E([" + p.X.String() + "," + p.Y.String() + "])" } -// IsInfinity checks if the point is infinity (in affine, it's encoded as (0,0)) +// IsInfinity checks if the point is infinity +// in affine, it's encoded as (0,0) +// (0,0) is never on the curve for j=0 curves func (p *G2Affine) IsInfinity() bool { return p.X.IsZero() && p.Y.IsZero() } @@ -157,17 +173,30 @@ func (p *G2Jac) Set(a *G2Jac) *G2Jac { // Equal tests if two points (in Jacobian coordinates) are equal func (p *G2Jac) Equal(a *G2Jac) bool { - - if p.Z.IsZero() && a.Z.IsZero() { - return true + // If one point is infinity, the other must also be infinity. + if p.Z.IsZero() { + return a.Z.IsZero() + } + // If the other point is infinity, return false since we can't + // the following checks would be incorrect. + if a.Z.IsZero() { + return false } - _p := G2Affine{} - _p.FromJacobian(p) - _a := G2Affine{} - _a.FromJacobian(a) + var pZSquare, aZSquare fptower.E2 + pZSquare.Square(&p.Z) + aZSquare.Square(&a.Z) - return _p.X.Equal(&_a.X) && _p.Y.Equal(&_a.Y) + var lhs, rhs fptower.E2 + lhs.Mul(&p.X, &aZSquare) + rhs.Mul(&a.X, &pZSquare) + if !lhs.Equal(&rhs) { + return false + } + lhs.Mul(&p.Y, &aZSquare).Mul(&lhs, &a.Z) + rhs.Mul(&a.Y, &pZSquare).Mul(&rhs, &p.Z) + + return lhs.Equal(&rhs) } // Neg computes -G @@ -177,7 +206,7 @@ func (p *G2Jac) Neg(a *G2Jac) *G2Jac { return p } -// SubAssign substracts two points on the curve +// SubAssign subtracts two points on the curve func (p *G2Jac) SubAssign(a *G2Jac) *G2Jac { var tmp G2Jac tmp.Set(a) @@ -244,7 +273,7 @@ func (p *G2Jac) AddAssign(a *G2Jac) *G2Jac { func (p *G2Jac) AddMixed(a *G2Affine) *G2Jac { //if a is infinity return p - if a.X.IsZero() && a.Y.IsZero() { + if a.IsInfinity() { return p } // p is infinity, return a @@ -328,24 +357,22 @@ func (p *G2Jac) DoubleAssign() *G2Jac { return p } -// ScalarMultiplication computes and returns p = a*s +// ScalarMultiplication computes and returns p = a ⋅ s // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) ScalarMultiplication(a *G2Jac, s *big.Int) *G2Jac { return p.mulGLV(a, s) } +// String returns canonical representation of the point in affine coordinates func (p *G2Jac) String() string { - if p.Z.IsZero() { - return "O" - } _p := G2Affine{} _p.FromJacobian(p) - return "E([" + _p.X.String() + "," + _p.Y.String() + "])," + return _p.String() } -// FromAffine sets p = Q, p in Jacboian, Q in affine +// FromAffine sets p = Q, p in Jacobian, Q in affine func (p *G2Jac) FromAffine(Q *G2Affine) *G2Jac { - if Q.X.IsZero() && Q.Y.IsZero() { + if Q.IsInfinity() { p.Z.SetZero() p.X.SetOne() p.Y.SetOne() @@ -372,25 +399,35 @@ func (p *G2Jac) IsOnCurve() bool { } // IsInSubGroup returns true if p is on the r-torsion, false otherwise. -// [r]P == 0 <==> Frob(P) == [6x^2]P +// https://eprint.iacr.org/2022/348.pdf, sec. 3 and 5.1 +// [r]P == 0 <==> [x₀+1]P + ψ([x₀]P) + ψ²([x₀]P) = ψ³([2x₀]P) func (p *G2Jac) IsInSubGroup() bool { - var a, res G2Jac - a.psi(p) - res.ScalarMultiplication(p, &fixedCoeff). - SubAssign(&a) + var a, b, c, res G2Jac + a.ScalarMultiplication(p, &xGen) + b.psi(&a) + a.AddAssign(p) + res.psi(&b) + c.Set(&res). + AddAssign(&b). + AddAssign(&a) + res.psi(&res). + Double(&res). + SubAssign(&c) return res.IsOnCurve() && res.Z.IsZero() - } -// mulWindowed 2-bits windowed exponentiation +// mulWindowed computes a 2-bits windowed scalar multiplication func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { var res G2Jac var ops [3]G2Jac - res.Set(&g2Infinity) ops[0].Set(a) + if s.Sign() == -1 { + ops[0].Neg(&ops[0]) + } + res.Set(&g2Infinity) ops[1].Double(&ops[0]) ops[2].Set(&ops[0]).AddAssign(&ops[1]) @@ -413,7 +450,7 @@ func (p *G2Jac) mulWindowed(a *G2Jac, s *big.Int) *G2Jac { } -// psi(p) = u o frob o u**-1 where u:E'->E iso from the twist to E +// ψ(p) = u o π o u⁻¹ where u:E'→E iso from the twist to E func (p *G2Jac) psi(a *G2Jac) *G2Jac { p.Set(a) p.X.Conjugate(&p.X).Mul(&p.X, &endo.u) @@ -422,14 +459,15 @@ func (p *G2Jac) psi(a *G2Jac) *G2Jac { return p } -// phi assigns p to phi(a) where phi: (x,y)->(ux,y), and returns p +// ϕ assigns p to ϕ(a) where ϕ: (x,y) → (w x,y), and returns p +// where w is a third root of unity in 𝔽p func (p *G2Jac) phi(a *G2Jac) *G2Jac { p.Set(a) p.X.MulByElement(&p.X, &thirdRootOneG2) return p } -// mulGLV performs scalar multiplication using GLV +// mulGLV computes the scalar multiplication using a windowed-GLV method // see https://www.iacr.org/archive/crypto2001/21390189.pdf func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { @@ -439,11 +477,11 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { res.Set(&g2Infinity) - // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0*a table[0].Set(a) table[3].phi(a) - // split the scalar, modifies +-a, phi(a) accordingly + // split the scalar, modifies ±a, ϕ(a) accordingly k := ecc.SplitScalar(s, &glvBasis) if k[0].Sign() == -1 { @@ -456,7 +494,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { } // precompute table (2 bits sliding window) - // table[b3b2b1b0-1] = b3b2*phi(a) + b1b0*a if b3b2b1b0 != 0 + // table[b3b2b1b0-1] = b3b2 ⋅ ϕ(a) + b1b0 ⋅ a if b3b2b1b0 != 0 table[1].Double(&table[0]) table[2].Set(&table[1]).AddAssign(&table[0]) table[4].Set(&table[3]).AddAssign(&table[0]) @@ -471,12 +509,20 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { table[13].Set(&table[11]).AddAssign(&table[1]) table[14].Set(&table[11]).AddAssign(&table[2]) - // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 bits long max - k1.SetBigInt(&k[0]).FromMont() - k2.SetBigInt(&k[1]).FromMont() + // bounds on the lattice base vectors guarantee that k1, k2 are len(r)/2 or len(r)/2+1 bits long max + // this is because we use a probabilistic scalar decomposition that replaces a division by a right-shift + k1 = k1.SetBigInt(&k[0]).Bits() + k2 = k2.SetBigInt(&k[1]).Bits() - // loop starts from len(k1)/2 due to the bounds - for i := int(math.Ceil(fr.Limbs/2. - 1)); i >= 0; i-- { + // we don't target constant-timeness so we check first if we increase the bounds or not + maxBit := k1.BitLen() + if k2.BitLen() > maxBit { + maxBit = k2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(k1)/2 or len(k1)/2+1 due to the bounds + for i := hiWordIndex; i >= 0; i-- { mask := uint64(3) << 62 for j := 0; j < 32; j++ { res.Double(&res).Double(&res) @@ -547,7 +593,11 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { return p } -// fromJacExtended sets Q in affine coords +func (p *g2JacExtended) IsZero() bool { + return p.ZZ.IsZero() +} + +// fromJacExtended sets Q in affine coordinates func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { if Q.ZZ.IsZero() { p.X = fptower.E2{} @@ -559,7 +609,7 @@ func (p *G2Affine) fromJacExtended(Q *g2JacExtended) *G2Affine { return p } -// fromJacExtended sets Q in Jacobian coords +// fromJacExtended sets Q in Jacobian coordinates func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { if Q.ZZ.IsZero() { p.Set(&g2Infinity) @@ -571,7 +621,7 @@ func (p *G2Jac) fromJacExtended(Q *g2JacExtended) *G2Jac { return p } -// unsafeFromJacExtended sets p in jacobian coords, but don't check for infinity +// unsafeFromJacExtended sets p in Jacobian coordinates, but don't check for infinity func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { p.X.Square(&Q.ZZ).Mul(&p.X, &Q.X) p.Y.Square(&Q.ZZZ).Mul(&p.Y, &Q.Y) @@ -579,7 +629,7 @@ func (p *G2Jac) unsafeFromJacExtended(Q *g2JacExtended) *G2Jac { return p } -// add point in ZZ coords +// add point in Jacobian extended coordinates // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { //if q is infinity return p @@ -592,15 +642,15 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } - var A, B, X1ZZ2, X2ZZ1, Y1ZZZ2, Y2ZZZ1 fptower.E2 + var A, B, U1, U2, S1, S2 fptower.E2 // p2: q, p1: p - X2ZZ1.Mul(&q.X, &p.ZZ) - X1ZZ2.Mul(&p.X, &q.ZZ) - A.Sub(&X2ZZ1, &X1ZZ2) - Y2ZZZ1.Mul(&q.Y, &p.ZZZ) - Y1ZZZ2.Mul(&p.Y, &q.ZZZ) - B.Sub(&Y2ZZZ1, &Y1ZZZ2) + U2.Mul(&q.X, &p.ZZ) + U1.Mul(&p.X, &q.ZZ) + A.Sub(&U2, &U1) + S2.Mul(&q.Y, &p.ZZZ) + S1.Mul(&p.Y, &q.ZZZ) + B.Sub(&S2, &S1) if A.IsZero() { if B.IsZero() { @@ -612,11 +662,7 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } - var U1, U2, S1, S2, P, R, PP, PPP, Q, V fptower.E2 - U1.Mul(&p.X, &q.ZZ) - U2.Mul(&q.X, &p.ZZ) - S1.Mul(&p.Y, &q.ZZZ) - S2.Mul(&q.Y, &p.ZZZ) + var P, R, PP, PPP, Q, V fptower.E2 P.Sub(&U2, &U1) R.Sub(&S2, &S1) PP.Square(&P) @@ -639,8 +685,10 @@ func (p *g2JacExtended) add(q *g2JacExtended) *g2JacExtended { return p } -// double point in ZZ coords +// double point in Jacobian extended coordinates // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 +// since we consider any point on Z=0 as the point at infinity +// this doubling formula works for infinity points as well func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { var U, V, W, S, XX, M fptower.E2 @@ -670,7 +718,7 @@ func (p *g2JacExtended) double(q *g2JacExtended) *g2JacExtended { func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p - if a.X.IsZero() && a.Y.IsZero() { + if a.IsInfinity() { return p } // p is infinity, return a @@ -726,7 +774,7 @@ func (p *g2JacExtended) subMixed(a *G2Affine) *g2JacExtended { func (p *g2JacExtended) addMixed(a *G2Affine) *g2JacExtended { //if a is infinity return p - if a.X.IsZero() && a.Y.IsZero() { + if a.IsInfinity() { return p } // p is infinity, return a @@ -803,7 +851,7 @@ func (p *g2JacExtended) doubleNegMixed(q *G2Affine) *g2JacExtended { return p } -// doubleMixed point in ZZ coords +// doubleMixed point in Jacobian extended coordinates // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 func (p *g2JacExtended) doubleMixed(q *G2Affine) *g2JacExtended { @@ -846,18 +894,6 @@ func (p *g2Proj) Neg(a *g2Proj) *g2Proj { return p } -// FromJacobian converts a point from Jacobian to projective coordinates -func (p *g2Proj) FromJacobian(Q *G2Jac) *g2Proj { - var buf fptower.E2 - buf.Square(&Q.Z) - - p.x.Mul(&Q.X, &Q.Z) - p.y.Set(&Q.Y) - p.z.Mul(&Q.Z, &buf) - - return p -} - // FromAffine sets p = Q, p in homogenous projective, Q in affine func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { if Q.X.IsZero() && Q.Y.IsZero() { @@ -872,97 +908,74 @@ func (p *g2Proj) FromAffine(Q *G2Affine) *g2Proj { return p } -// BatchScalarMultiplicationG2 multiplies the same base (generator) by all scalars +// BatchScalarMultiplicationG2 multiplies the same base by all scalars // and return resulting points in affine coordinates // uses a simple windowed-NAF like exponentiation algorithm func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affine { - // approximate cost in group ops is // cost = 2^{c-1} + n(scalar.nbBits+nbChunks) nbPoints := uint64(len(scalars)) min := ^uint64(0) bestC := 0 - for c := 2; c < 18; c++ { - cost := uint64(1 << (c - 1)) - nbChunks := uint64(fr.Limbs * 64 / c) - if (fr.Limbs*64)%c != 0 { - nbChunks++ - } - cost += nbPoints * ((fr.Limbs * 64) + nbChunks) + for c := 2; c <= 16; c++ { + cost := uint64(1 << (c - 1)) // pre compute the table + nbChunks := computeNbChunks(uint64(c)) + cost += nbPoints * (uint64(c) + 1) * nbChunks // doublings + point add if cost < min { min = cost bestC = c } } c := uint64(bestC) // window size - nbChunks := int(fr.Limbs * 64 / c) - if (fr.Limbs*64)%c != 0 { - nbChunks++ + nbChunks := int(computeNbChunks(c)) + + // last window may be slightly larger than c; in which case we need to compute one + // extra element in the baseTable + maxC := lastC(c) + if c > maxC { + maxC = c } - mask := uint64((1 << c) - 1) // low c bits are 1 - msbWindow := uint64(1 << (c - 1)) // precompute all powers of base for our window // note here that if performance is critical, we can implement as in the msmX methods // this allocation to be on the stack - baseTable := make([]G2Jac, (1 << (c - 1))) - baseTable[0].Set(&g2Infinity) - baseTable[0].AddMixed(base) + baseTable := make([]G2Jac, (1 << (maxC - 1))) + baseTable[0].FromAffine(base) for i := 1; i < len(baseTable); i++ { baseTable[i] = baseTable[i-1] baseTable[i].AddMixed(base) } - - pScalars, _ := partitionScalars(scalars, c, false, runtime.NumCPU()) - - // compute offset and word selector / shift to select the right bits of our windows - selectors := make([]selector, nbChunks) - for chunk := 0; chunk < nbChunks; chunk++ { - jc := uint64(uint64(chunk) * c) - d := selector{} - d.index = jc / 64 - d.shift = jc - (d.index * 64) - d.mask = mask << d.shift - d.multiWordSelect = (64%c) != 0 && d.shift > (64-c) && d.index < (fr.Limbs-1) - if d.multiWordSelect { - nbBitsHigh := d.shift - uint64(64-c) - d.maskHigh = (1 << nbBitsHigh) - 1 - d.shiftHigh = (c - nbBitsHigh) - } - selectors[chunk] = d - } toReturn := make([]G2Affine, len(scalars)) - // for each digit, take value in the base table, double it c time, voila. - parallel.Execute(len(pScalars), func(start, end int) { + // partition the scalars into digits + digits, _ := partitionScalars(scalars, c, runtime.NumCPU()) + + // for each digit, take value in the base table, double it c time, voilà. + parallel.Execute(len(scalars), func(start, end int) { var p G2Jac for i := start; i < end; i++ { p.Set(&g2Infinity) for chunk := nbChunks - 1; chunk >= 0; chunk-- { - s := selectors[chunk] if chunk != nbChunks-1 { for j := uint64(0); j < c; j++ { p.DoubleAssign() } } + offset := chunk * len(scalars) + digit := digits[i+offset] - bits := (pScalars[i][s.index] & s.mask) >> s.shift - if s.multiWordSelect { - bits += (pScalars[i][s.index+1] & s.maskHigh) << s.shiftHigh - } - - if bits == 0 { + if digit == 0 { continue } - // if msbWindow bit is set, we need to substract - if bits&msbWindow == 0 { + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { // add - p.AddAssign(&baseTable[bits-1]) + p.AddAssign(&baseTable[(digit>>1)-1]) } else { // sub - t := baseTable[bits & ^msbWindow] + t := baseTable[digit>>1] t.Neg(&t) p.AddAssign(&t) } @@ -975,3 +988,54 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin }) return toReturn } + +// batch add affine coordinates +// using batch inversion +// special cases (doubling, infinity) must be filtered out before this call +func batchAddG2Affine[TP pG2Affine, TPP ppG2Affine, TC cG2Affine](R *TPP, P *TP, batchSize int) { + var lambda, lambdain TC + + // add part + for j := 0; j < batchSize; j++ { + lambdain[j].Sub(&(*P)[j].X, &(*R)[j].X) + } + + // invert denominator using montgomery batch invert technique + { + var accumulator fptower.E2 + lambda[0].SetOne() + accumulator.Set(&lambdain[0]) + + for i := 1; i < batchSize; i++ { + lambda[i] = accumulator + accumulator.Mul(&accumulator, &lambdain[i]) + } + + accumulator.Inverse(&accumulator) + + for i := batchSize - 1; i > 0; i-- { + lambda[i].Mul(&lambda[i], &accumulator) + accumulator.Mul(&accumulator, &lambdain[i]) + } + lambda[0].Set(&accumulator) + } + + var d fptower.E2 + var rr G2Affine + + // add part + for j := 0; j < batchSize; j++ { + // computa lambda + d.Sub(&(*P)[j].Y, &(*R)[j].Y) + lambda[j].Mul(&lambda[j], &d) + + // compute X, Y + rr.X.Square(&lambda[j]) + rr.X.Sub(&rr.X, &(*R)[j].X) + rr.X.Sub(&rr.X, &(*P)[j].X) + d.Sub(&(*R)[j].X, &rr.X) + rr.Y.Mul(&lambda[j], &d) + rr.Y.Sub(&rr.Y, &(*R)[j].Y) + (*R)[j].Set(&rr) + } +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_curve.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_curve.go deleted file mode 100644 index 14fe62a0707..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_curve.go +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright 2020 ConsenSys AG -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package bn254 - -import ( - "math/big" - - "github.com/consensys/gnark-crypto/ecc" - "github.com/consensys/gnark-crypto/ecc/bn254/fp" - "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" -) - -// hashToFp hashes msg to count prime field elements. -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5.2 -func hashToFp(msg, dst []byte, count int) ([]fp.Element, error) { - - // 128 bits of security - // L = ceil((ceil(log2(p)) + k) / 8), where k is the security parameter = 128 - L := 48 - - lenInBytes := count * L - pseudoRandomBytes, err := ecc.ExpandMsgXmd(msg, dst, lenInBytes) - if err != nil { - return nil, err - } - - res := make([]fp.Element, count) - for i := 0; i < count; i++ { - res[i].SetBytes(pseudoRandomBytes[i*L : (i+1)*L]) - } - return res, nil -} - -// returns false if u>-u when seen as a bigInt -func sign0(u fp.Element) bool { - var a, b big.Int - u.ToBigIntRegular(&a) - u.Neg(&u) - u.ToBigIntRegular(&b) - return a.Cmp(&b) <= 0 -} - -// ---------------------------------------------------------------------------------------- -// G1Affine - -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-4.1 -// Shallue and van de Woestijne method, works for any elliptic curve in Weierstrass curve -func svdwMapG1(u fp.Element) G1Affine { - - var res G1Affine - - // constants - // sage script to find z: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-E.1 - var z, c1, c2, c3, c4 fp.Element - z.SetOne() - c1.SetString("4") - c2.SetString("10944121435919637611123202872628637544348155578648911831344518947322613104291") - c3.SetString("8815841940592487685674414971303048083897117035520822607866") - c4.SetString("7296080957279758407415468581752425029565437052432607887563012631548408736189") - - var tv1, tv2, tv3, tv4, one, x1, gx1, x2, gx2, x3, x, gx, y fp.Element - one.SetOne() - tv1.Square(&u).Mul(&tv1, &c1) - tv2.Add(&one, &tv1) - tv1.Sub(&one, &tv1) - tv3.Mul(&tv2, &tv1).Inverse(&tv3) - tv4.Mul(&u, &tv1) - tv4.Mul(&tv4, &tv3) - tv4.Mul(&tv4, &c3) - x1.Sub(&c2, &tv4) - gx1.Square(&x1) - // 12. gx1 = gx1 + A - gx1.Mul(&gx1, &x1) - gx1.Add(&gx1, &bCurveCoeff) - e1 := gx1.Legendre() - x2.Add(&c2, &tv4) - gx2.Square(&x2) - // 18. gx2 = gx2 + A - gx2.Mul(&gx2, &x2) - gx2.Add(&gx2, &bCurveCoeff) - e2 := gx2.Legendre() - e1 // 2 if is_square(gx2) AND NOT e1 - x3.Square(&tv2) - x3.Mul(&x3, &tv3) - x3.Square(&x3) - x3.Mul(&x3, &c4) - x3.Add(&x3, &z) - if e1 == 1 { - x.Set(&x1) - } else { - x.Set(&x3) - } - if e2 == 2 { - x.Set(&x2) - } - gx.Square(&x) - // gx = gx + A - gx.Mul(&gx, &x) - gx.Add(&gx, &bCurveCoeff) - y.Sqrt(&gx) - e3 := sign0(u) && sign0(y) - if !e3 { - y.Neg(&y) - } - res.X.Set(&x) - res.Y.Set(&y) - - return res -} - -// MapToCurveG1Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.1 -func MapToCurveG1Svdw(t fp.Element) G1Affine { - res := svdwMapG1(t) - return res -} - -// EncodeToCurveG1Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.2 -func EncodeToCurveG1Svdw(msg, dst []byte) (G1Affine, error) { - var res G1Affine - t, err := hashToFp(msg, dst, 1) - if err != nil { - return res, err - } - res = MapToCurveG1Svdw(t[0]) - return res, nil -} - -// HashToCurveG1Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-3 -func HashToCurveG1Svdw(msg, dst []byte) (G1Affine, error) { - var res G1Affine - u, err := hashToFp(msg, dst, 2) - if err != nil { - return res, err - } - Q0 := MapToCurveG1Svdw(u[0]) - Q1 := MapToCurveG1Svdw(u[1]) - var _Q0, _Q1, _res G1Jac - _Q0.FromAffine(&Q0) - _Q1.FromAffine(&Q1) - _res.Set(&_Q1).AddAssign(&_Q0) - res.FromJacobian(&_res) - return res, nil -} - -// ---------------------------------------------------------------------------------------- -// G2Affine - -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-4.1 -// Shallue and van de Woestijne method, works for any elliptic curve in Weierstrass curve -func svdwMapG2(u fptower.E2) G2Affine { - - var res G2Affine - - // constants - // sage script to find z: https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-E.1 - var z, c1, c2, c3, c4 fptower.E2 - z.A1.SetString("1") - c1.A0.SetString("19485874751759354771024239261021720505790618469301721065564631296452457478373") - c1.A1.SetString("266929791119991161246907387137283842545076965332900288569378510910307636689") - c2.A1.SetString("10944121435919637611123202872628637544348155578648911831344518947322613104291") - c3.A0.SetString("13617985070220897759416741581922326973608167195618746963957740978229330444385") - c3.A1.SetString("6485072654231349560354894037339044590945718224403932749563131108378844487223") - c4.A0.SetString("18685085378399381287283517099609868978155387573303020199856495763721534568303") - c4.A1.SetString("355906388159988214995876516183045123393435953777200384759171347880410182252") - - var tv1, tv2, tv3, tv4, one, x1, gx1, x2, gx2, x3, x, gx, y fptower.E2 - one.SetOne() - tv1.Square(&u).Mul(&tv1, &c1) - tv2.Add(&one, &tv1) - tv1.Sub(&one, &tv1) - tv3.Mul(&tv2, &tv1).Inverse(&tv3) - tv4.Mul(&u, &tv1) - tv4.Mul(&tv4, &tv3) - tv4.Mul(&tv4, &c3) - x1.Sub(&c2, &tv4) - gx1.Square(&x1) - // 12. gx1 = gx1 + A - gx1.Mul(&gx1, &x1) - gx1.Add(&gx1, &bTwistCurveCoeff) - e1 := gx1.Legendre() - x2.Add(&c2, &tv4) - gx2.Square(&x2) - // 18. gx2 = gx2 + A - gx2.Mul(&gx2, &x2) - gx2.Add(&gx2, &bTwistCurveCoeff) - e2 := gx2.Legendre() - e1 // 2 if is_square(gx2) AND NOT e1 - x3.Square(&tv2) - x3.Mul(&x3, &tv3) - x3.Square(&x3) - x3.Mul(&x3, &c4) - x3.Add(&x3, &z) - if e1 == 1 { - x.Set(&x1) - } else { - x.Set(&x3) - } - if e2 == 2 { - x.Set(&x2) - } - gx.Square(&x) - // gx = gx + A - gx.Mul(&gx, &x) - gx.Add(&gx, &bTwistCurveCoeff) - y.Sqrt(&gx) - e3 := sign0(u.A0) && sign0(y.A0) - if !e3 { - y.Neg(&y) - } - res.X.Set(&x) - res.Y.Set(&y) - - return res -} - -// MapToCurveG2Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.1 -func MapToCurveG2Svdw(t fptower.E2) G2Affine { - res := svdwMapG2(t) - res.ClearCofactor(&res) - return res -} - -// EncodeToCurveG2Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-2.2.2 -func EncodeToCurveG2Svdw(msg, dst []byte) (G2Affine, error) { - var res G2Affine - _t, err := hashToFp(msg, dst, 2) - if err != nil { - return res, err - } - var t fptower.E2 - t.A0.Set(&_t[0]) - t.A1.Set(&_t[1]) - res = MapToCurveG2Svdw(t) - return res, nil -} - -// HashToCurveG2Svdw maps an fp.Element to a point on the curve using the Shallue and van de Woestijne map -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-3 -func HashToCurveG2Svdw(msg, dst []byte) (G2Affine, error) { - var res G2Affine - u, err := hashToFp(msg, dst, 4) - if err != nil { - return res, err - } - var u0, u1 fptower.E2 - u0.A0.Set(&u[0]) - u0.A1.Set(&u[1]) - u1.A0.Set(&u[2]) - u1.A1.Set(&u[3]) - Q0 := MapToCurveG2Svdw(u0) - Q1 := MapToCurveG2Svdw(u1) - var _Q0, _Q1, _res G2Jac - _Q0.FromAffine(&Q0) - _Q1.FromAffine(&Q1) - _res.Set(&_Q1).AddAssign(&_Q0) - res.FromJacobian(&_res) - return res, nil -} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g1.go new file mode 100644 index 00000000000..6be3be8e103 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g1.go @@ -0,0 +1,161 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fp" +) + +// MapToCurve1 implements the Shallue and van de Woestijne method, applicable to any elliptic curve in Weierstrass form +// No cofactor clearing or isogeny +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-svdw +func MapToCurve1(u *fp.Element) G1Affine { + var tv1, tv2, tv3, tv4 fp.Element + var x1, x2, x3, gx1, gx2, gx, x, y fp.Element + var one fp.Element + var gx1NotSquare, gx1SquareOrGx2Not int + + //constants + //c1 = g(Z) + //c2 = -Z / 2 + //c3 = sqrt(-g(Z) * (3 * Z² + 4 * A)) # sgn0(c3) MUST equal 0 + //c4 = -4 * g(Z) / (3 * Z² + 4 * A) + + Z := fp.Element{15230403791020821917, 754611498739239741, 7381016538464732716, 1011752739694698287} + c1 := fp.Element{1248766071674976557, 10548065924188627562, 16242874202584236114, 560012691975822483} + c2 := fp.Element{12997850613838968789, 14304628359724097447, 2950087706404981016, 1237622763554136189} + c3 := fp.Element{8972444824031832946, 5898165201680709844, 10690697896010808308, 824354360198587078} + c4 := fp.Element{12077013577332951089, 1872782865047492001, 13514471836495169457, 415649166299893576} + + one.SetOne() + + tv1.Square(u) // 1. tv1 = u² + tv1.Mul(&tv1, &c1) // 2. tv1 = tv1 * c1 + tv2.Add(&one, &tv1) // 3. tv2 = 1 + tv1 + tv1.Sub(&one, &tv1) // 4. tv1 = 1 - tv1 + tv3.Mul(&tv1, &tv2) // 5. tv3 = tv1 * tv2 + + tv3.Inverse(&tv3) // 6. tv3 = inv0(tv3) + tv4.Mul(u, &tv1) // 7. tv4 = u * tv1 + tv4.Mul(&tv4, &tv3) // 8. tv4 = tv4 * tv3 + tv4.Mul(&tv4, &c3) // 9. tv4 = tv4 * c3 + x1.Sub(&c2, &tv4) // 10. x1 = c2 - tv4 + + gx1.Square(&x1) // 11. gx1 = x1² + //12. gx1 = gx1 + A All curves in gnark-crypto have A=0 (j-invariant=0). It is crucial to include this step if the curve has nonzero A coefficient. + gx1.Mul(&gx1, &x1) // 13. gx1 = gx1 * x1 + gx1.Add(&gx1, &bCurveCoeff) // 14. gx1 = gx1 + B + gx1NotSquare = gx1.Legendre() >> 1 // 15. e1 = is_square(gx1) + // gx1NotSquare = 0 if gx1 is a square, -1 otherwise + + x2.Add(&c2, &tv4) // 16. x2 = c2 + tv4 + gx2.Square(&x2) // 17. gx2 = x2² + // 18. gx2 = gx2 + A See line 12 + gx2.Mul(&gx2, &x2) // 19. gx2 = gx2 * x2 + gx2.Add(&gx2, &bCurveCoeff) // 20. gx2 = gx2 + B + + { + gx2NotSquare := gx2.Legendre() >> 1 // gx2Square = 0 if gx2 is a square, -1 otherwise + gx1SquareOrGx2Not = gx2NotSquare | ^gx1NotSquare // 21. e2 = is_square(gx2) AND NOT e1 # Avoid short-circuit logic ops + } + + x3.Square(&tv2) // 22. x3 = tv2² + x3.Mul(&x3, &tv3) // 23. x3 = x3 * tv3 + x3.Square(&x3) // 24. x3 = x3² + x3.Mul(&x3, &c4) // 25. x3 = x3 * c4 + + x3.Add(&x3, &Z) // 26. x3 = x3 + Z + x.Select(gx1NotSquare, &x1, &x3) // 27. x = CMOV(x3, x1, e1) # x = x1 if gx1 is square, else x = x3 + // Select x1 iff gx1 is square iff gx1NotSquare = 0 + x.Select(gx1SquareOrGx2Not, &x2, &x) // 28. x = CMOV(x, x2, e2) # x = x2 if gx2 is square and gx1 is not + // Select x2 iff gx2 is square and gx1 is not, iff gx1SquareOrGx2Not = 0 + gx.Square(&x) // 29. gx = x² + // 30. gx = gx + A + + gx.Mul(&gx, &x) // 31. gx = gx * x + gx.Add(&gx, &bCurveCoeff) // 32. gx = gx + B + + y.Sqrt(&gx) // 33. y = sqrt(gx) + signsNotEqual := g1Sgn0(u) ^ g1Sgn0(&y) // 34. e3 = sgn0(u) == sgn0(y) + + tv1.Neg(&y) + y.Select(int(signsNotEqual), &y, &tv1) // 35. y = CMOV(-y, y, e3) # Select correct sign of y + return G1Affine{x, y} +} + +// g1Sgn0 is an algebraic substitute for the notion of sign in ordered fields +// Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function +// The sign of an element is not obviously related to that of its Montgomery form +func g1Sgn0(z *fp.Element) uint64 { + + nonMont := z.Bits() + + // m == 1 + return nonMont[0] % 2 + +} + +// MapToG1 invokes the SVDW map, and guarantees that the result is in g1 +func MapToG1(u fp.Element) G1Affine { + res := MapToCurve1(&u) + return res +} + +// EncodeToG1 hashes a message to a point on the G1 curve using the SVDW map. +// It is faster than HashToG1, but the result is not uniformly distributed. Unsuitable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func EncodeToG1(msg, dst []byte) (G1Affine, error) { + + var res G1Affine + u, err := fp.Hash(msg, dst, 1) + if err != nil { + return res, err + } + + res = MapToCurve1(&u[0]) + + return res, nil +} + +// HashToG1 hashes a message to a point on the G1 curve using the SVDW map. +// Slower than EncodeToG1, but usable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func HashToG1(msg, dst []byte) (G1Affine, error) { + u, err := fp.Hash(msg, dst, 2*1) + if err != nil { + return G1Affine{}, err + } + + Q0 := MapToCurve1(&u[0]) + Q1 := MapToCurve1(&u[1]) + + var _Q0, _Q1 G1Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1).AddAssign(&_Q0) + + Q1.FromJacobian(&_Q1) + return Q1, nil +} + +func g1NotZero(x *fp.Element) uint64 { + + return x[0] | x[1] | x[2] | x[3] + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g2.go new file mode 100644 index 00000000000..fa81853d03a --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/hash_to_g2.go @@ -0,0 +1,205 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" +) + +// MapToCurve2 implements the Shallue and van de Woestijne method, applicable to any elliptic curve in Weierstrass form +// No cofactor clearing or isogeny +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#straightline-svdw +func MapToCurve2(u *fptower.E2) G2Affine { + var tv1, tv2, tv3, tv4 fptower.E2 + var x1, x2, x3, gx1, gx2, gx, x, y fptower.E2 + var one fptower.E2 + var gx1NotSquare, gx1SquareOrGx2Not int + + //constants + //c1 = g(Z) + //c2 = -Z / 2 + //c3 = sqrt(-g(Z) * (3 * Z² + 4 * A)) # sgn0(c3) MUST equal 0 + //c4 = -4 * g(Z) / (3 * Z² + 4 * A) + + Z := fptower.E2{ + A0: fp.Element{15230403791020821917, 754611498739239741, 7381016538464732716, 1011752739694698287}, + A1: fp.Element{0}, + } + c1 := fptower.E2{ + A0: fp.Element{15219334786797146878, 8431472696017589261, 15336528771359260718, 196732871012706162}, + A1: fp.Element{4100506350182530919, 7345568344173317438, 15513160039642431658, 90557763186888013}, + } + c2 := fptower.E2{ + A0: fp.Element{12997850613838968789, 14304628359724097447, 2950087706404981016, 1237622763554136189}, + A1: fp.Element{0}, + } + c3 := fptower.E2{ + A0: fp.Element{12298500088583694207, 17447120171744064890, 14097510924717921191, 2278398337453771183}, + A1: fp.Element{4693446565795584099, 18320164443970680666, 6792758484113206563, 2989688171181581768}, + } + c4 := fptower.E2{ + A0: fp.Element{7191623630069643826, 8333948550768170742, 13001081703983517696, 2062355016518372226}, + A1: fp.Element{11163104453509316115, 7271947710149976975, 4894807947557820282, 3366254582553786647}, + } + + one.SetOne() + + tv1.Square(u) // 1. tv1 = u² + tv1.Mul(&tv1, &c1) // 2. tv1 = tv1 * c1 + tv2.Add(&one, &tv1) // 3. tv2 = 1 + tv1 + tv1.Sub(&one, &tv1) // 4. tv1 = 1 - tv1 + tv3.Mul(&tv1, &tv2) // 5. tv3 = tv1 * tv2 + + tv3.Inverse(&tv3) // 6. tv3 = inv0(tv3) + tv4.Mul(u, &tv1) // 7. tv4 = u * tv1 + tv4.Mul(&tv4, &tv3) // 8. tv4 = tv4 * tv3 + tv4.Mul(&tv4, &c3) // 9. tv4 = tv4 * c3 + x1.Sub(&c2, &tv4) // 10. x1 = c2 - tv4 + + gx1.Square(&x1) // 11. gx1 = x1² + //12. gx1 = gx1 + A All curves in gnark-crypto have A=0 (j-invariant=0). It is crucial to include this step if the curve has nonzero A coefficient. + gx1.Mul(&gx1, &x1) // 13. gx1 = gx1 * x1 + gx1.Add(&gx1, &bTwistCurveCoeff) // 14. gx1 = gx1 + B + gx1NotSquare = gx1.Legendre() >> 1 // 15. e1 = is_square(gx1) + // gx1NotSquare = 0 if gx1 is a square, -1 otherwise + + x2.Add(&c2, &tv4) // 16. x2 = c2 + tv4 + gx2.Square(&x2) // 17. gx2 = x2² + // 18. gx2 = gx2 + A See line 12 + gx2.Mul(&gx2, &x2) // 19. gx2 = gx2 * x2 + gx2.Add(&gx2, &bTwistCurveCoeff) // 20. gx2 = gx2 + B + + { + gx2NotSquare := gx2.Legendre() >> 1 // gx2Square = 0 if gx2 is a square, -1 otherwise + gx1SquareOrGx2Not = gx2NotSquare | ^gx1NotSquare // 21. e2 = is_square(gx2) AND NOT e1 # Avoid short-circuit logic ops + } + + x3.Square(&tv2) // 22. x3 = tv2² + x3.Mul(&x3, &tv3) // 23. x3 = x3 * tv3 + x3.Square(&x3) // 24. x3 = x3² + x3.Mul(&x3, &c4) // 25. x3 = x3 * c4 + + x3.Add(&x3, &Z) // 26. x3 = x3 + Z + x.Select(gx1NotSquare, &x1, &x3) // 27. x = CMOV(x3, x1, e1) # x = x1 if gx1 is square, else x = x3 + // Select x1 iff gx1 is square iff gx1NotSquare = 0 + x.Select(gx1SquareOrGx2Not, &x2, &x) // 28. x = CMOV(x, x2, e2) # x = x2 if gx2 is square and gx1 is not + // Select x2 iff gx2 is square and gx1 is not, iff gx1SquareOrGx2Not = 0 + gx.Square(&x) // 29. gx = x² + // 30. gx = gx + A + + gx.Mul(&gx, &x) // 31. gx = gx * x + gx.Add(&gx, &bTwistCurveCoeff) // 32. gx = gx + B + + y.Sqrt(&gx) // 33. y = sqrt(gx) + signsNotEqual := g2Sgn0(u) ^ g2Sgn0(&y) // 34. e3 = sgn0(u) == sgn0(y) + + tv1.Neg(&y) + y.Select(int(signsNotEqual), &y, &tv1) // 35. y = CMOV(-y, y, e3) # Select correct sign of y + return G2Affine{x, y} +} + +// g2Sgn0 is an algebraic substitute for the notion of sign in ordered fields +// Namely, every non-zero quadratic residue in a finite field of characteristic =/= 2 has exactly two square roots, one of each sign +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-the-sgn0-function +// The sign of an element is not obviously related to that of its Montgomery form +func g2Sgn0(z *fptower.E2) uint64 { + + nonMont := z.Bits() + + sign := uint64(0) // 1. sign = 0 + zero := uint64(1) // 2. zero = 1 + var signI uint64 + var zeroI uint64 + + // 3. i = 1 + signI = nonMont.A0[0] % 2 // 4. sign_i = x_i mod 2 + zeroI = g1NotZero(&nonMont.A0) + zeroI = 1 ^ (zeroI|-zeroI)>>63 // 5. zero_i = x_i == 0 + sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops + zero = zero & zeroI // 7. zero = zero AND zero_i + // 3. i = 2 + signI = nonMont.A1[0] % 2 // 4. sign_i = x_i mod 2 + // 5. zero_i = x_i == 0 + sign = sign | (zero & signI) // 6. sign = sign OR (zero AND sign_i) # Avoid short-circuit logic ops + // 7. zero = zero AND zero_i + return sign + +} + +// MapToG2 invokes the SVDW map, and guarantees that the result is in g2 +func MapToG2(u fptower.E2) G2Affine { + res := MapToCurve2(&u) + res.ClearCofactor(&res) + return res +} + +// EncodeToG2 hashes a message to a point on the G2 curve using the SVDW map. +// It is faster than HashToG2, but the result is not uniformly distributed. Unsuitable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func EncodeToG2(msg, dst []byte) (G2Affine, error) { + + var res G2Affine + u, err := fp.Hash(msg, dst, 2) + if err != nil { + return res, err + } + + res = MapToCurve2(&fptower.E2{ + A0: u[0], + A1: u[1], + }) + + res.ClearCofactor(&res) + return res, nil +} + +// HashToG2 hashes a message to a point on the G2 curve using the SVDW map. +// Slower than EncodeToG2, but usable as a random oracle. +// dst stands for "domain separation tag", a string unique to the construction using the hash function +// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#roadmap +func HashToG2(msg, dst []byte) (G2Affine, error) { + u, err := fp.Hash(msg, dst, 2*2) + if err != nil { + return G2Affine{}, err + } + + Q0 := MapToCurve2(&fptower.E2{ + A0: u[0], + A1: u[1], + }) + Q1 := MapToCurve2(&fptower.E2{ + A0: u[2+0], + A1: u[2+1], + }) + + var _Q0, _Q1 G2Jac + _Q0.FromAffine(&Q0) + _Q1.FromAffine(&Q1).AddAssign(&_Q0) + + _Q1.ClearCofactor(&_Q1) + + Q1.FromJacobian(&_Q1) + return Q1, nil +} + +func g2NotZero(x *fptower.E2) uint64 { + //Assuming G1 is over Fp and that if hashing is available for G2, it also is for G1 + return g1NotZero(&x.A0) | g1NotZero(&x.A1) + +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm.go index 0ec192019d8..49751a93969 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm.go @@ -1,7 +1,7 @@ //go:build !noadx // +build !noadx -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm_noadx.go index 6a09c11c492..c6a97081fca 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm_noadx.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/asm_noadx.go @@ -1,7 +1,7 @@ //go:build noadx // +build noadx -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12.go index 3f8c763fb80..a9f6d28e9b4 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,18 +17,26 @@ package fptower import ( - "encoding/binary" "errors" + "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "math/big" + "sync" ) +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + // E12 is a degree two finite field extension of fp6 type E12 struct { C0, C1 E6 } -// Equal returns true if z equals x, fasle otherwise +// Equal returns true if z equals x, false otherwise func (z *E12) Equal(x *E12) bool { return z.C0.Equal(&x.C0) && z.C1.Equal(&x.C1) } @@ -59,20 +67,6 @@ func (z *E12) SetOne() *E12 { return z } -// ToMont converts to Mont form -func (z *E12) ToMont() *E12 { - z.C0.ToMont() - z.C1.ToMont() - return z -} - -// FromMont converts from Mont form -func (z *E12) FromMont() *E12 { - z.C0.FromMont() - z.C1.FromMont() - return z -} - // Add set z=x+y in E12 and return z func (z *E12) Add(x, y *E12) *E12 { z.C0.Add(&x.C0, &y.C0) @@ -105,6 +99,15 @@ func (z *E12) SetRandom() (*E12, error) { return z, nil } +// IsZero returns true if the two elements are equal, false otherwise +func (z *E12) IsZero() bool { + return z.C0.IsZero() && z.C1.IsZero() +} + +func (z *E12) IsOne() bool { + return z.C0.IsOne() && z.C1.IsZero() +} + // Mul set z=x*y in E12 and return z func (z *E12) Mul(x, y *E12) *E12 { var a, b, c E6 @@ -210,29 +213,51 @@ func (z *E12) CyclotomicSquareCompressed(x *E12) *E12 { return z } -// Decompress Karabina's cyclotomic square result -func (z *E12) Decompress(x *E12) *E12 { +// DecompressKarabina Karabina's cyclotomic square result +// if g3 != 0 +// +// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 +// +// if g3 == 0 +// +// g4 = 2g1g5/g2 +// +// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) +// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} +func (z *E12) DecompressKarabina(x *E12) *E12 { var t [3]E2 var one E2 one.SetOne() - // t0 = g1^2 - t[0].Square(&x.C0.B1) - // t1 = 3 * g1^2 - 2 * g2 - t[1].Sub(&t[0], &x.C0.B2). - Double(&t[1]). - Add(&t[1], &t[0]) - // t0 = E * g5^2 + t1 - t[2].Square(&x.C1.B2) - t[0].MulByNonResidue(&t[2]). - Add(&t[0], &t[1]) - // t1 = 1/(4 * g3) - t[1].Double(&x.C1.B0). - Double(&t[1]). - Inverse(&t[1]) // costly + if x.C1.B2.IsZero() /* g3 == 0 */ { + t[0].Mul(&x.C0.B1, &x.C1.B2). + Double(&t[0]) + // t1 = g2 + t[1].Set(&x.C0.B2) + + if t[1].IsZero() /* g2 == g3 == 0 */ { + return z.SetOne() + } + } else /* g3 != 0 */ { + + // t0 = g1^2 + t[0].Square(&x.C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t[1].Sub(&t[0], &x.C0.B2). + Double(&t[1]). + Add(&t[1], &t[0]) + // t0 = E * g5^2 + t1 + t[2].Square(&x.C1.B2) + t[0].MulByNonResidue(&t[2]). + Add(&t[0], &t[1]) + // t1 = 4 * g3 + t[1].Double(&x.C1.B0). + Double(&t[1]) + } + // z4 = g4 - z.C1.B1.Mul(&t[0], &t[1]) + z.C1.B1.Div(&t[0], &t[1]) // costly // t1 = g2 * g1 t[1].Mul(&x.C0.B2, &x.C0.B1) @@ -241,7 +266,7 @@ func (z *E12) Decompress(x *E12) *E12 { Sub(&t[2], &t[1]). Double(&t[2]). Sub(&t[2], &t[1]) - // t1 = g3 * g5 + // t1 = g3 * g5 (g3 can be 0) t[1].Mul(&x.C1.B0, &x.C1.B2) // c_0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 t[2].Add(&t[2], &t[1]) @@ -256,8 +281,20 @@ func (z *E12) Decompress(x *E12) *E12 { return z } -// BatchDecompress multiple Karabina's cyclotomic square results -func BatchDecompress(x []E12) []E12 { +// BatchDecompressKarabina multiple Karabina's cyclotomic square results +// if g3 != 0 +// +// g4 = (E * g5^2 + 3 * g1^2 - 2 * g2)/4g3 +// +// if g3 == 0 +// +// g4 = 2g1g5/g2 +// +// if g3=g2=0 then g4=g5=g1=0 and g0=1 (x=1) +// Theorem 3.1 is well-defined for all x in Gϕₙ\{1} +// +// Divisions by 4g3 or g2 is batched using Montgomery batch inverse +func BatchDecompressKarabina(x []E12) []E12 { n := len(x) if n == 0 { @@ -267,29 +304,47 @@ func BatchDecompress(x []E12) []E12 { t0 := make([]E2, n) t1 := make([]E2, n) t2 := make([]E2, n) + zeroes := make([]bool, n) var one E2 one.SetOne() for i := 0; i < n; i++ { - // t0 = g1^2 - t0[i].Square(&x[i].C0.B1) - // t1 = 3 * g1^2 - 2 * g2 - t1[i].Sub(&t0[i], &x[i].C0.B2). - Double(&t1[i]). - Add(&t1[i], &t0[i]) - // t0 = E * g5^2 + t1 - t2[i].Square(&x[i].C1.B2) - t0[i].MulByNonResidue(&t2[i]). - Add(&t0[i], &t1[i]) - // t1 = 4 * g3 - t1[i].Double(&x[i].C1.B0). - Double(&t1[i]) + if x[i].C1.B2.IsZero() /* g3 == 0 */ { + t0[i].Mul(&x[i].C0.B1, &x[i].C1.B2). + Double(&t0[i]) + // t1 = g2 + t1[i].Set(&x[i].C0.B2) + + if t1[i].IsZero() /* g3 == g2 == 0 */ { + x[i].SetOne() + zeroes[i] = true + continue + } + } else /* g3 != 0 */ { + // t0 = g1^2 + t0[i].Square(&x[i].C0.B1) + // t1 = 3 * g1^2 - 2 * g2 + t1[i].Sub(&t0[i], &x[i].C0.B2). + Double(&t1[i]). + Add(&t1[i], &t0[i]) + // t0 = E * g5^2 + t1 + t2[i].Square(&x[i].C1.B2) + t0[i].MulByNonResidue(&t2[i]). + Add(&t0[i], &t1[i]) + // t1 = 4 * g3 + t1[i].Double(&x[i].C1.B0). + Double(&t1[i]) + } } - t1 = BatchInvert(t1) // costs 1 inverse + t1 = BatchInvertE2(t1) // costs 1 inverse for i := 0; i < n; i++ { + if zeroes[i] { + continue + } + // z4 = g4 x[i].C1.B1.Mul(&t0[i], &t1[i]) @@ -301,7 +356,7 @@ func BatchDecompress(x []E12) []E12 { t2[i].Double(&t2[i]) t2[i].Sub(&t2[i], &t1[i]) - // t1 = g3 * g5 + // t1 = g3 * g5 (g3s can be 0s) t1[i].Mul(&x[i].C1.B0, &x[i].C1.B2) // z0 = E * (2 * g4^2 + g3 * g5 - 3 * g2 * g1) + 1 t2[i].Add(&t2[i], &t1[i]) @@ -352,6 +407,8 @@ func (z *E12) CyclotomicSquare(x *E12) *E12 { } // Inverse set z to the inverse of x in E12 and return z +// +// if x == 0, sets and returns z = x func (z *E12) Inverse(x *E12) *E12 { // Algorithm 23 from https://eprint.iacr.org/2010/354.pdf @@ -367,22 +424,213 @@ func (z *E12) Inverse(x *E12) *E12 { return z } -// Exp sets z=x**e and returns it -func (z *E12) Exp(x *E12, e big.Int) *E12 { +// BatchInvertE12 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE12(a []E12) []E12 { + res := make([]E12, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E12 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +// Exp sets z=xᵏ (mod q¹²) and returns it +// uses 2-bits windowed method +func (z *E12) Exp(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + var res E12 + var ops [3]E12 + res.SetOne() + ops[0].Set(&x) + ops[1].Square(&ops[0]) + ops[2].Set(&ops[0]).Mul(&ops[2], &ops[1]) + b := e.Bytes() for i := range b { w := b[i] - mask := byte(0x80) - for j := 7; j >= 0; j-- { - res.Square(&res) - if (w&mask)>>j != 0 { - res.Mul(&res, x) + mask := byte(0xc0) + for j := 0; j < 4; j++ { + res.Square(&res).Square(&res) + c := (w & mask) >> (6 - 2*j) + if c != 0 { + res.Mul(&res, &ops[c-1]) + } + mask = mask >> 2 + } + } + z.Set(&res) + + return z +} + +// CyclotomicExp sets z=xᵏ (mod q¹²) and returns it +// uses 2-NAF decomposition +// x must be in the cyclotomic subgroup +// TODO: use a windowed method +func (z *E12) CyclotomicExp(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert (=conjugate) + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Conjugate(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var res, xInv E12 + xInv.InverseUnitary(&x) + res.SetOne() + eNAF := make([]int8, e.BitLen()+3) + n := ecc.NafDecomposition(e, eNAF[:]) + for i := n - 1; i >= 0; i-- { + res.CyclotomicSquare(&res) + if eNAF[i] == 1 { + res.Mul(&res, &x) + } else if eNAF[i] == -1 { + res.Mul(&res, &xInv) + } + } + z.Set(&res) + return z +} + +// ExpGLV sets z=xᵏ (q¹²) and returns it +// uses 2-dimensional GLV with 2-bits windowed method +// x must be in GT +// TODO: use 2-NAF +// TODO: use higher dimensional decomposition +func (z *E12) ExpGLV(x E12, k *big.Int) *E12 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert (=conjugate) + // if k < 0: xᵏ (mod q¹²) == (x⁻¹)ᵏ (mod q¹²) + x.Conjugate(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + + var table [15]E12 + var res E12 + var s1, s2 fr.Element + + res.SetOne() + + // table[b3b2b1b0-1] = b3b2*Frobinius(x) + b1b0*x + table[0].Set(&x) + table[3].Frobenius(&x) + + // split the scalar, modifies ±x, Frob(x) accordingly + s := ecc.SplitScalar(e, &glvBasis) + + if s[0].Sign() == -1 { + s[0].Neg(&s[0]) + table[0].InverseUnitary(&table[0]) + } + if s[1].Sign() == -1 { + s[1].Neg(&s[1]) + table[3].InverseUnitary(&table[3]) + } + + // precompute table (2 bits sliding window) + // table[b3b2b1b0-1] = b3b2*Frobenius(x) + b1b0*x if b3b2b1b0 != 0 + table[1].CyclotomicSquare(&table[0]) + table[2].Mul(&table[1], &table[0]) + table[4].Mul(&table[3], &table[0]) + table[5].Mul(&table[3], &table[1]) + table[6].Mul(&table[3], &table[2]) + table[7].CyclotomicSquare(&table[3]) + table[8].Mul(&table[7], &table[0]) + table[9].Mul(&table[7], &table[1]) + table[10].Mul(&table[7], &table[2]) + table[11].Mul(&table[7], &table[3]) + table[12].Mul(&table[11], &table[0]) + table[13].Mul(&table[11], &table[1]) + table[14].Mul(&table[11], &table[2]) + + // bounds on the lattice base vectors guarantee that s1, s2 are len(r)/2 bits long max + s1 = s1.SetBigInt(&s[0]).Bits() + s2 = s2.SetBigInt(&s[1]).Bits() + + maxBit := s1.BitLen() + if s2.BitLen() > maxBit { + maxBit = s2.BitLen() + } + hiWordIndex := (maxBit - 1) / 64 + + // loop starts from len(s1)/2 due to the bounds + for i := hiWordIndex; i >= 0; i-- { + mask := uint64(3) << 62 + for j := 0; j < 32; j++ { + res.CyclotomicSquare(&res).CyclotomicSquare(&res) + b1 := (s1[i] & mask) >> (62 - 2*j) + b2 := (s2[i] & mask) >> (62 - 2*j) + if b1|b2 != 0 { + s := (b2<<2 | b1) + res.Mul(&res, &table[s-1]) } - mask = mask >> 1 + mask = mask >> 2 } } + z.Set(&res) return z } @@ -408,76 +656,27 @@ func (z *E12) Marshal() []byte { return b[:] } -// Unmarshal is an allias to SetBytes() +// Unmarshal is an alias to SetBytes() func (z *E12) Unmarshal(buf []byte) error { return z.SetBytes(buf) } // Bytes returns the regular (non montgomery) value // of z as a big-endian byte array. -// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... func (z *E12) Bytes() (r [SizeOfGT]byte) { - _z := *z - _z.FromMont() - binary.BigEndian.PutUint64(r[376:384], _z.C0.B0.A0[0]) - binary.BigEndian.PutUint64(r[368:376], _z.C0.B0.A0[1]) - binary.BigEndian.PutUint64(r[360:368], _z.C0.B0.A0[2]) - binary.BigEndian.PutUint64(r[352:360], _z.C0.B0.A0[3]) - - binary.BigEndian.PutUint64(r[344:352], _z.C0.B0.A1[0]) - binary.BigEndian.PutUint64(r[336:344], _z.C0.B0.A1[1]) - binary.BigEndian.PutUint64(r[328:336], _z.C0.B0.A1[2]) - binary.BigEndian.PutUint64(r[320:328], _z.C0.B0.A1[3]) - - binary.BigEndian.PutUint64(r[312:320], _z.C0.B1.A0[0]) - binary.BigEndian.PutUint64(r[304:312], _z.C0.B1.A0[1]) - binary.BigEndian.PutUint64(r[296:304], _z.C0.B1.A0[2]) - binary.BigEndian.PutUint64(r[288:296], _z.C0.B1.A0[3]) - - binary.BigEndian.PutUint64(r[280:288], _z.C0.B1.A1[0]) - binary.BigEndian.PutUint64(r[272:280], _z.C0.B1.A1[1]) - binary.BigEndian.PutUint64(r[264:272], _z.C0.B1.A1[2]) - binary.BigEndian.PutUint64(r[256:264], _z.C0.B1.A1[3]) - - binary.BigEndian.PutUint64(r[248:256], _z.C0.B2.A0[0]) - binary.BigEndian.PutUint64(r[240:248], _z.C0.B2.A0[1]) - binary.BigEndian.PutUint64(r[232:240], _z.C0.B2.A0[2]) - binary.BigEndian.PutUint64(r[224:232], _z.C0.B2.A0[3]) - - binary.BigEndian.PutUint64(r[216:224], _z.C0.B2.A1[0]) - binary.BigEndian.PutUint64(r[208:216], _z.C0.B2.A1[1]) - binary.BigEndian.PutUint64(r[200:208], _z.C0.B2.A1[2]) - binary.BigEndian.PutUint64(r[192:200], _z.C0.B2.A1[3]) - - binary.BigEndian.PutUint64(r[184:192], _z.C1.B0.A0[0]) - binary.BigEndian.PutUint64(r[176:184], _z.C1.B0.A0[1]) - binary.BigEndian.PutUint64(r[168:176], _z.C1.B0.A0[2]) - binary.BigEndian.PutUint64(r[160:168], _z.C1.B0.A0[3]) - - binary.BigEndian.PutUint64(r[152:160], _z.C1.B0.A1[0]) - binary.BigEndian.PutUint64(r[144:152], _z.C1.B0.A1[1]) - binary.BigEndian.PutUint64(r[136:144], _z.C1.B0.A1[2]) - binary.BigEndian.PutUint64(r[128:136], _z.C1.B0.A1[3]) - - binary.BigEndian.PutUint64(r[120:128], _z.C1.B1.A0[0]) - binary.BigEndian.PutUint64(r[112:120], _z.C1.B1.A0[1]) - binary.BigEndian.PutUint64(r[104:112], _z.C1.B1.A0[2]) - binary.BigEndian.PutUint64(r[96:104], _z.C1.B1.A0[3]) - - binary.BigEndian.PutUint64(r[88:96], _z.C1.B1.A1[0]) - binary.BigEndian.PutUint64(r[80:88], _z.C1.B1.A1[1]) - binary.BigEndian.PutUint64(r[72:80], _z.C1.B1.A1[2]) - binary.BigEndian.PutUint64(r[64:72], _z.C1.B1.A1[3]) - - binary.BigEndian.PutUint64(r[56:64], _z.C1.B2.A0[0]) - binary.BigEndian.PutUint64(r[48:56], _z.C1.B2.A0[1]) - binary.BigEndian.PutUint64(r[40:48], _z.C1.B2.A0[2]) - binary.BigEndian.PutUint64(r[32:40], _z.C1.B2.A0[3]) - - binary.BigEndian.PutUint64(r[24:32], _z.C1.B2.A1[0]) - binary.BigEndian.PutUint64(r[16:24], _z.C1.B2.A1[1]) - binary.BigEndian.PutUint64(r[8:16], _z.C1.B2.A1[2]) - binary.BigEndian.PutUint64(r[0:8], _z.C1.B2.A1[3]) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[352:352+fp.Bytes]), z.C0.B0.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[320:320+fp.Bytes]), z.C0.B0.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[288:288+fp.Bytes]), z.C0.B1.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[256:256+fp.Bytes]), z.C0.B1.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[224:224+fp.Bytes]), z.C0.B2.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[192:192+fp.Bytes]), z.C0.B2.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[160:160+fp.Bytes]), z.C1.B0.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[128:128+fp.Bytes]), z.C1.B0.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[96:96+fp.Bytes]), z.C1.B1.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[64:64+fp.Bytes]), z.C1.B1.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[32:32+fp.Bytes]), z.C1.B2.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(r[0:0+fp.Bytes]), z.C1.B2.A1) return } @@ -485,48 +684,174 @@ func (z *E12) Bytes() (r [SizeOfGT]byte) { // SetBytes interprets e as the bytes of a big-endian GT // sets z to that value (in Montgomery form), and returns z. // size(e) == 32 * 12 -// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... +// z.C1.B2.A1 | z.C1.B2.A0 | z.C1.B1.A1 | ... func (z *E12) SetBytes(e []byte) error { if len(e) != SizeOfGT { return errors.New("invalid buffer size") } - z.C0.B0.A0.SetBytes(e[352 : 352+fp.Bytes]) + if err := z.C0.B0.A0.SetBytesCanonical(e[352 : 352+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B0.A1.SetBytesCanonical(e[320 : 320+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B1.A0.SetBytesCanonical(e[288 : 288+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B1.A1.SetBytesCanonical(e[256 : 256+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B2.A0.SetBytesCanonical(e[224 : 224+fp.Bytes]); err != nil { + return err + } + if err := z.C0.B2.A1.SetBytesCanonical(e[192 : 192+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B0.A0.SetBytesCanonical(e[160 : 160+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B0.A1.SetBytesCanonical(e[128 : 128+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B1.A0.SetBytesCanonical(e[96 : 96+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B1.A1.SetBytesCanonical(e[64 : 64+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B2.A0.SetBytesCanonical(e[32 : 32+fp.Bytes]); err != nil { + return err + } + if err := z.C1.B2.A1.SetBytesCanonical(e[0 : 0+fp.Bytes]); err != nil { + return err + } - z.C0.B0.A1.SetBytes(e[320 : 320+fp.Bytes]) + return nil +} - z.C0.B1.A0.SetBytes(e[288 : 288+fp.Bytes]) +// IsInSubGroup ensures GT/E12 is in correct subgroup +func (z *E12) IsInSubGroup() bool { + var a, b, _b E12 - z.C0.B1.A1.SetBytes(e[256 : 256+fp.Bytes]) + a.Frobenius(z) + b.Expt(z). + Expt(&b). + CyclotomicSquare(&b) + _b.CyclotomicSquare(&b) + b.Mul(&b, &_b) - z.C0.B2.A0.SetBytes(e[224 : 224+fp.Bytes]) + return a.Equal(&b) +} - z.C0.B2.A1.SetBytes(e[192 : 192+fp.Bytes]) +// CompressTorus GT/E12 element to half its size +// z must be in the cyclotomic subgroup +// i.e. z^(p^4-p^2+1)=1 +// e.g. GT +// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG +// z.C1 == 0 only when z \in {-1,1} +func (z *E12) CompressTorus() (E6, error) { - z.C1.B0.A0.SetBytes(e[160 : 160+fp.Bytes]) + if z.C1.IsZero() { + return E6{}, errors.New("invalid input") + } - z.C1.B0.A1.SetBytes(e[128 : 128+fp.Bytes]) + var res, tmp, one E6 + one.SetOne() + tmp.Inverse(&z.C1) + res.Add(&z.C0, &one). + Mul(&res, &tmp) - z.C1.B1.A0.SetBytes(e[96 : 96+fp.Bytes]) + return res, nil +} - z.C1.B1.A1.SetBytes(e[64 : 64+fp.Bytes]) +// BatchCompressTorus GT/E12 elements to half their size using a batch inversion. +// +// if len(x) == 0 or if any of the x[i].C1 coordinate is 0, this function returns an error. +func BatchCompressTorus(x []E12) ([]E6, error) { - z.C1.B2.A0.SetBytes(e[32 : 32+fp.Bytes]) + n := len(x) + if n == 0 { + return nil, errors.New("invalid input size") + } - z.C1.B2.A1.SetBytes(e[0 : 0+fp.Bytes]) + var one E6 + one.SetOne() + res := make([]E6, n) - return nil + for i := 0; i < n; i++ { + res[i].Set(&x[i].C1) + // throw an error if any of the x[i].C1 is 0 + if res[i].IsZero() { + return nil, errors.New("invalid input; C1 is 0") + } + } + + t := BatchInvertE6(res) // costs 1 inverse + + for i := 0; i < n; i++ { + res[i].Add(&x[i].C0, &one). + Mul(&res[i], &t[i]) + } + + return res, nil } -// IsInSubGroup ensures GT/E12 is in correct sugroup -func (z *E12) IsInSubGroup() bool { - var a, b, _b E12 +// DecompressTorus GT/E12 a compressed element +// element must be in the cyclotomic subgroup +// "COMPRESSION IN FINITE FIELDS AND TORUS-BASED CRYPTOGRAPHY", K. RUBIN AND A. SILVERBERG +func (z *E6) DecompressTorus() E12 { - a.Frobenius(z) - b.Expt(z). - Expt(&b). - CyclotomicSquare(&b) - _b.CyclotomicSquare(&b) - b.Mul(&b, &_b) + var res, num, denum E12 + num.C0.Set(z) + num.C1.SetOne() + denum.C0.Set(z) + denum.C1.SetOne().Neg(&denum.C1) + res.Inverse(&denum). + Mul(&res, &num) - return a.Equal(&b) + return res +} + +// BatchDecompressTorus GT/E12 compressed elements +// using a batch inversion +func BatchDecompressTorus(x []E6) ([]E12, error) { + + n := len(x) + if n == 0 { + return []E12{}, errors.New("invalid input size") + } + + res := make([]E12, n) + num := make([]E12, n) + denum := make([]E12, n) + + for i := 0; i < n; i++ { + num[i].C0.Set(&x[i]) + num[i].C1.SetOne() + denum[i].C0.Set(&x[i]) + denum[i].C1.SetOne().Neg(&denum[i].C1) + } + + denum = BatchInvertE12(denum) // costs 1 inverse + + for i := 0; i < n; i++ { + res[i].Mul(&num[i], &denum[i]) + } + + return res, nil +} + +func (z *E12) Select(cond int, caseZ *E12, caseNz *E12) *E12 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.C0.Select(cond, &caseZ.C0, &caseNz.C0) + z.C1.Select(cond, &caseZ.C1, &caseNz.C1) + + return z +} + +func (z *E12) Div(x *E12, y *E12) *E12 { + var r E12 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) } diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12_pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12_pairing.go index b29bc3fefcb..78c94d2f613 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12_pairing.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e12_pairing.go @@ -12,7 +12,7 @@ func (z *E12) nSquareCompressed(n int) { } } -// Expt set z to x^t in E12 and return z (t is the generator of the curve) +// Expt set z to xᵗ (mod q¹²) and return z (t is the generator of the curve) func (z *E12) Expt(x *E12) *E12 { // Expt computation is derived from the addition chain: // @@ -153,8 +153,8 @@ func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 { } // Mul034By034 multiplication of sparse element (c0,0,0,c3,c4,0) by sparse element (d0,0,0,d3,d4,0) -func (z *E12) Mul034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { - var tmp, x0, x3, x4, x04, x03, x34 E2 +func Mul034By034(d0, d3, d4, c0, c3, c4 *E2) [5]E2 { + var z00, tmp, x0, x3, x4, x04, x03, x34 E2 x0.Mul(c0, d0) x3.Mul(c3, d3) x4.Mul(c4, d4) @@ -174,13 +174,30 @@ func (z *E12) Mul034by034(d0, d3, d4, c0, c3, c4 *E2) *E12 { Sub(&x34, &x3). Sub(&x34, &x4) - z.C0.B0.MulByNonResidue(&x4). - Add(&z.C0.B0, &x0) - z.C0.B1.Set(&x3) - z.C0.B2.Set(&x34) - z.C1.B0.Set(&x03) - z.C1.B1.Set(&x04) - z.C1.B2.SetZero() + z00.MulByNonResidue(&x4). + Add(&z00, &x0) + + return [5]E2{z00, x3, x34, x03, x04} +} + +// MulBy01234 multiplies z by an E12 sparse element of the form (x0, x1, x2, x3, x4, 0) +func (z *E12) MulBy01234(x *[5]E2) *E12 { + var c1, a, b, c, z0, z1 E6 + c0 := &E6{B0: x[0], B1: x[1], B2: x[2]} + c1.B0 = x[3] + c1.B1 = x[4] + a.Add(&z.C0, &z.C1) + b.Add(c0, &c1) + a.Mul(&a, &b) + b.Mul(&z.C0, c0) + c.Set(&z.C1).MulBy01(&x[3], &x[4]) + z1.Sub(&a, &b) + z1.Sub(&z1, &c) + z0.MulByNonResidue(&c) + z0.Add(&z0, &b) + + z.C0 = z0 + z.C1 = z1 return z } diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2.go index 9c1b4c7aff3..8c16efc9375 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -26,17 +26,25 @@ type E2 struct { A0, A1 fp.Element } -// Equal returns true if z equals x, fasle otherwise +// Equal returns true if z equals x, false otherwise func (z *E2) Equal(x *E2) bool { return z.A0.Equal(&x.A0) && z.A1.Equal(&x.A1) } +// Bits +// TODO @gbotrel fixme this shouldn't return a E2 +func (z *E2) Bits() E2 { + r := E2{} + r.A0 = z.A0.Bits() + r.A1 = z.A1.Bits() + return r +} + // Cmp compares (lexicographic order) z and x and returns: // -// -1 if z < x -// 0 if z == x -// +1 if z > x -// +// -1 if z < x +// 0 if z == x +// +1 if z > x func (z *E2) Cmp(x *E2) int { if a1 := z.A1.Cmp(&x.A1); a1 != 0 { return a1 @@ -93,11 +101,15 @@ func (z *E2) SetRandom() (*E2, error) { return z, nil } -// IsZero returns true if the two elements are equal, fasle otherwise +// IsZero returns true if the two elements are equal, false otherwise func (z *E2) IsZero() bool { return z.A0.IsZero() && z.A1.IsZero() } +func (z *E2) IsOne() bool { + return z.A0.IsOne() && z.A1.IsZero() +} + // Add adds two elements of E2 func (z *E2) Add(x, y *E2) *E2 { addE2(z, x, y) @@ -124,21 +136,7 @@ func (z *E2) Neg(x *E2) *E2 { // String implements Stringer interface for fancy printing func (z *E2) String() string { - return (z.A0.String() + "+" + z.A1.String() + "*u") -} - -// ToMont converts to mont form -func (z *E2) ToMont() *E2 { - z.A0.ToMont() - z.A1.ToMont() - return z -} - -// FromMont converts from mont form -func (z *E2) FromMont() *E2 { - z.A0.FromMont() - z.A1.FromMont() - return z + return z.A0.String() + "+" + z.A1.String() + "*u" } // MulByElement multiplies an element in E2 by an element in fp @@ -170,10 +168,27 @@ func (z *E2) Legendre() int { return n.Legendre() } -// Exp sets z=x**e and returns it -func (z *E2) Exp(x E2, exponent *big.Int) *E2 { +// Exp sets z=xᵏ (mod q²) and returns it +func (z *E2) Exp(x E2, k *big.Int) *E2 { + if k.IsUint64() && k.Uint64() == 0 { + return z.SetOne() + } + + e := k + if k.Sign() == -1 { + // negative k, we invert + // if k < 0: xᵏ (mod q²) == (x⁻¹)ᵏ (mod q²) + x.Inverse(&x) + + // we negate k in a temp big.Int since + // Int.Bit(_) of k and -k is different + e = bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(e) + e.Neg(k) + } + z.SetOne() - b := exponent.Bytes() + b := e.Bytes() for i := 0; i < len(b); i++ { w := b[i] for j := 0; j < 8; j++ { @@ -199,7 +214,7 @@ func init() { var sqrtExp1, sqrtExp2 big.Int // Sqrt sets z to the square root of and returns z -// The function does not test wether the square root +// The function does not test whether the square root // exists or not, it's up to the caller to call // Legendre beforehand. // cf https://eprint.iacr.org/2012/685.pdf (algo 9) @@ -228,9 +243,11 @@ func (z *E2) Sqrt(x *E2) *E2 { return z } -// BatchInvert returns a new slice with every element inverted. +// BatchInvertE2 returns a new slice with every element inverted. // Uses Montgomery batch inversion trick -func BatchInvert(a []E2) []E2 { +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE2(a []E2) []E2 { res := make([]E2, len(a)) if len(a) == 0 { return res @@ -261,3 +278,18 @@ func BatchInvert(a []E2) []E2 { return res } + +func (z *E2) Select(cond int, caseZ *E2, caseNz *E2) *E2 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.A0.Select(cond, &caseZ.A0, &caseNz.A0) + z.A1.Select(cond, &caseZ.A1, &caseNz.A1) + + return z +} + +func (z *E2) Div(x *E2, y *E2) *E2 { + var r E2 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_adx_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_adx_amd64.s deleted file mode 100644 index aabff96ad1a..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_adx_amd64.s +++ /dev/null @@ -1,732 +0,0 @@ -// +build amd64_adx - -// Copyright 2020 ConsenSys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "textflag.h" -#include "funcdata.h" - -// modulus q -DATA q<>+0(SB)/8, $0x3c208c16d87cfd47 -DATA q<>+8(SB)/8, $0x97816a916871ca8d -DATA q<>+16(SB)/8, $0xb85045b68181585d -DATA q<>+24(SB)/8, $0x30644e72e131a029 -GLOBL q<>(SB), (RODATA+NOPTR), $32 - -// qInv0 q'[0] -DATA qInv0<>(SB)/8, $0x87d20782e4866389 -GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 - -#define REDUCE(ra0, ra1, ra2, ra3, rb0, rb1, rb2, rb3) \ - MOVQ ra0, rb0; \ - SUBQ q<>(SB), ra0; \ - MOVQ ra1, rb1; \ - SBBQ q<>+8(SB), ra1; \ - MOVQ ra2, rb2; \ - SBBQ q<>+16(SB), ra2; \ - MOVQ ra3, rb3; \ - SBBQ q<>+24(SB), ra3; \ - CMOVQCS rb0, ra0; \ - CMOVQCS rb1, ra1; \ - CMOVQCS rb2, ra2; \ - CMOVQCS rb3, ra3; \ - -// this code is generated and identical to fp.Mul(...) -#define MUL() \ - XORQ AX, AX; \ - MOVQ SI, DX; \ - MULXQ R14, R10, R11; \ - MULXQ R15, AX, R12; \ - ADOXQ AX, R11; \ - MULXQ CX, AX, R13; \ - ADOXQ AX, R12; \ - MULXQ BX, AX, BP; \ - ADOXQ AX, R13; \ - MOVQ $0, AX; \ - ADOXQ AX, BP; \ - PUSHQ BP; \ - MOVQ qInv0<>(SB), DX; \ - IMULQ R10, DX; \ - XORQ AX, AX; \ - MULXQ q<>+0(SB), AX, BP; \ - ADCXQ R10, AX; \ - MOVQ BP, R10; \ - POPQ BP; \ - ADCXQ R11, R10; \ - MULXQ q<>+8(SB), AX, R11; \ - ADOXQ AX, R10; \ - ADCXQ R12, R11; \ - MULXQ q<>+16(SB), AX, R12; \ - ADOXQ AX, R11; \ - ADCXQ R13, R12; \ - MULXQ q<>+24(SB), AX, R13; \ - ADOXQ AX, R12; \ - MOVQ $0, AX; \ - ADCXQ AX, R13; \ - ADOXQ BP, R13; \ - XORQ AX, AX; \ - MOVQ DI, DX; \ - MULXQ R14, AX, BP; \ - ADOXQ AX, R10; \ - ADCXQ BP, R11; \ - MULXQ R15, AX, BP; \ - ADOXQ AX, R11; \ - ADCXQ BP, R12; \ - MULXQ CX, AX, BP; \ - ADOXQ AX, R12; \ - ADCXQ BP, R13; \ - MULXQ BX, AX, BP; \ - ADOXQ AX, R13; \ - MOVQ $0, AX; \ - ADCXQ AX, BP; \ - ADOXQ AX, BP; \ - PUSHQ BP; \ - MOVQ qInv0<>(SB), DX; \ - IMULQ R10, DX; \ - XORQ AX, AX; \ - MULXQ q<>+0(SB), AX, BP; \ - ADCXQ R10, AX; \ - MOVQ BP, R10; \ - POPQ BP; \ - ADCXQ R11, R10; \ - MULXQ q<>+8(SB), AX, R11; \ - ADOXQ AX, R10; \ - ADCXQ R12, R11; \ - MULXQ q<>+16(SB), AX, R12; \ - ADOXQ AX, R11; \ - ADCXQ R13, R12; \ - MULXQ q<>+24(SB), AX, R13; \ - ADOXQ AX, R12; \ - MOVQ $0, AX; \ - ADCXQ AX, R13; \ - ADOXQ BP, R13; \ - XORQ AX, AX; \ - MOVQ R8, DX; \ - MULXQ R14, AX, BP; \ - ADOXQ AX, R10; \ - ADCXQ BP, R11; \ - MULXQ R15, AX, BP; \ - ADOXQ AX, R11; \ - ADCXQ BP, R12; \ - MULXQ CX, AX, BP; \ - ADOXQ AX, R12; \ - ADCXQ BP, R13; \ - MULXQ BX, AX, BP; \ - ADOXQ AX, R13; \ - MOVQ $0, AX; \ - ADCXQ AX, BP; \ - ADOXQ AX, BP; \ - PUSHQ BP; \ - MOVQ qInv0<>(SB), DX; \ - IMULQ R10, DX; \ - XORQ AX, AX; \ - MULXQ q<>+0(SB), AX, BP; \ - ADCXQ R10, AX; \ - MOVQ BP, R10; \ - POPQ BP; \ - ADCXQ R11, R10; \ - MULXQ q<>+8(SB), AX, R11; \ - ADOXQ AX, R10; \ - ADCXQ R12, R11; \ - MULXQ q<>+16(SB), AX, R12; \ - ADOXQ AX, R11; \ - ADCXQ R13, R12; \ - MULXQ q<>+24(SB), AX, R13; \ - ADOXQ AX, R12; \ - MOVQ $0, AX; \ - ADCXQ AX, R13; \ - ADOXQ BP, R13; \ - XORQ AX, AX; \ - MOVQ R9, DX; \ - MULXQ R14, AX, BP; \ - ADOXQ AX, R10; \ - ADCXQ BP, R11; \ - MULXQ R15, AX, BP; \ - ADOXQ AX, R11; \ - ADCXQ BP, R12; \ - MULXQ CX, AX, BP; \ - ADOXQ AX, R12; \ - ADCXQ BP, R13; \ - MULXQ BX, AX, BP; \ - ADOXQ AX, R13; \ - MOVQ $0, AX; \ - ADCXQ AX, BP; \ - ADOXQ AX, BP; \ - PUSHQ BP; \ - MOVQ qInv0<>(SB), DX; \ - IMULQ R10, DX; \ - XORQ AX, AX; \ - MULXQ q<>+0(SB), AX, BP; \ - ADCXQ R10, AX; \ - MOVQ BP, R10; \ - POPQ BP; \ - ADCXQ R11, R10; \ - MULXQ q<>+8(SB), AX, R11; \ - ADOXQ AX, R10; \ - ADCXQ R12, R11; \ - MULXQ q<>+16(SB), AX, R12; \ - ADOXQ AX, R11; \ - ADCXQ R13, R12; \ - MULXQ q<>+24(SB), AX, R13; \ - ADOXQ AX, R12; \ - MOVQ $0, AX; \ - ADCXQ AX, R13; \ - ADOXQ BP, R13; \ - -TEXT ·addE2(SB), NOSPLIT, $0-24 - MOVQ x+8(FP), AX - MOVQ 0(AX), BX - MOVQ 8(AX), SI - MOVQ 16(AX), DI - MOVQ 24(AX), R8 - MOVQ y+16(FP), DX - ADDQ 0(DX), BX - ADCQ 8(DX), SI - ADCQ 16(DX), DI - ADCQ 24(DX), R8 - - // reduce element(BX,SI,DI,R8) using temp registers (R9,R10,R11,R12) - REDUCE(BX,SI,DI,R8,R9,R10,R11,R12) - - MOVQ res+0(FP), CX - MOVQ BX, 0(CX) - MOVQ SI, 8(CX) - MOVQ DI, 16(CX) - MOVQ R8, 24(CX) - MOVQ 32(AX), BX - MOVQ 40(AX), SI - MOVQ 48(AX), DI - MOVQ 56(AX), R8 - ADDQ 32(DX), BX - ADCQ 40(DX), SI - ADCQ 48(DX), DI - ADCQ 56(DX), R8 - - // reduce element(BX,SI,DI,R8) using temp registers (R13,R14,R15,R9) - REDUCE(BX,SI,DI,R8,R13,R14,R15,R9) - - MOVQ BX, 32(CX) - MOVQ SI, 40(CX) - MOVQ DI, 48(CX) - MOVQ R8, 56(CX) - RET - -TEXT ·doubleE2(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DX - MOVQ x+8(FP), AX - MOVQ 0(AX), CX - MOVQ 8(AX), BX - MOVQ 16(AX), SI - MOVQ 24(AX), DI - ADDQ CX, CX - ADCQ BX, BX - ADCQ SI, SI - ADCQ DI, DI - - // reduce element(CX,BX,SI,DI) using temp registers (R8,R9,R10,R11) - REDUCE(CX,BX,SI,DI,R8,R9,R10,R11) - - MOVQ CX, 0(DX) - MOVQ BX, 8(DX) - MOVQ SI, 16(DX) - MOVQ DI, 24(DX) - MOVQ 32(AX), CX - MOVQ 40(AX), BX - MOVQ 48(AX), SI - MOVQ 56(AX), DI - ADDQ CX, CX - ADCQ BX, BX - ADCQ SI, SI - ADCQ DI, DI - - // reduce element(CX,BX,SI,DI) using temp registers (R12,R13,R14,R15) - REDUCE(CX,BX,SI,DI,R12,R13,R14,R15) - - MOVQ CX, 32(DX) - MOVQ BX, 40(DX) - MOVQ SI, 48(DX) - MOVQ DI, 56(DX) - RET - -TEXT ·subE2(SB), NOSPLIT, $0-24 - XORQ DI, DI - MOVQ x+8(FP), SI - MOVQ 0(SI), AX - MOVQ 8(SI), DX - MOVQ 16(SI), CX - MOVQ 24(SI), BX - MOVQ y+16(FP), SI - SUBQ 0(SI), AX - SBBQ 8(SI), DX - SBBQ 16(SI), CX - SBBQ 24(SI), BX - MOVQ x+8(FP), SI - MOVQ $0x3c208c16d87cfd47, R8 - MOVQ $0x97816a916871ca8d, R9 - MOVQ $0xb85045b68181585d, R10 - MOVQ $0x30644e72e131a029, R11 - CMOVQCC DI, R8 - CMOVQCC DI, R9 - CMOVQCC DI, R10 - CMOVQCC DI, R11 - ADDQ R8, AX - ADCQ R9, DX - ADCQ R10, CX - ADCQ R11, BX - MOVQ res+0(FP), R12 - MOVQ AX, 0(R12) - MOVQ DX, 8(R12) - MOVQ CX, 16(R12) - MOVQ BX, 24(R12) - MOVQ 32(SI), AX - MOVQ 40(SI), DX - MOVQ 48(SI), CX - MOVQ 56(SI), BX - MOVQ y+16(FP), SI - SUBQ 32(SI), AX - SBBQ 40(SI), DX - SBBQ 48(SI), CX - SBBQ 56(SI), BX - MOVQ $0x3c208c16d87cfd47, R13 - MOVQ $0x97816a916871ca8d, R14 - MOVQ $0xb85045b68181585d, R15 - MOVQ $0x30644e72e131a029, R8 - CMOVQCC DI, R13 - CMOVQCC DI, R14 - CMOVQCC DI, R15 - CMOVQCC DI, R8 - ADDQ R13, AX - ADCQ R14, DX - ADCQ R15, CX - ADCQ R8, BX - MOVQ res+0(FP), SI - MOVQ AX, 32(SI) - MOVQ DX, 40(SI) - MOVQ CX, 48(SI) - MOVQ BX, 56(SI) - RET - -TEXT ·negE2(SB), NOSPLIT, $0-16 - MOVQ res+0(FP), DX - MOVQ x+8(FP), AX - MOVQ 0(AX), BX - MOVQ 8(AX), SI - MOVQ 16(AX), DI - MOVQ 24(AX), R8 - MOVQ BX, AX - ORQ SI, AX - ORQ DI, AX - ORQ R8, AX - TESTQ AX, AX - JNE l1 - MOVQ AX, 0(DX) - MOVQ AX, 8(DX) - MOVQ AX, 16(DX) - MOVQ AX, 24(DX) - JMP l3 - -l1: - MOVQ $0x3c208c16d87cfd47, CX - SUBQ BX, CX - MOVQ CX, 0(DX) - MOVQ $0x97816a916871ca8d, CX - SBBQ SI, CX - MOVQ CX, 8(DX) - MOVQ $0xb85045b68181585d, CX - SBBQ DI, CX - MOVQ CX, 16(DX) - MOVQ $0x30644e72e131a029, CX - SBBQ R8, CX - MOVQ CX, 24(DX) - -l3: - MOVQ x+8(FP), AX - MOVQ 32(AX), BX - MOVQ 40(AX), SI - MOVQ 48(AX), DI - MOVQ 56(AX), R8 - MOVQ BX, AX - ORQ SI, AX - ORQ DI, AX - ORQ R8, AX - TESTQ AX, AX - JNE l2 - MOVQ AX, 32(DX) - MOVQ AX, 40(DX) - MOVQ AX, 48(DX) - MOVQ AX, 56(DX) - RET - -l2: - MOVQ $0x3c208c16d87cfd47, CX - SUBQ BX, CX - MOVQ CX, 32(DX) - MOVQ $0x97816a916871ca8d, CX - SBBQ SI, CX - MOVQ CX, 40(DX) - MOVQ $0xb85045b68181585d, CX - SBBQ DI, CX - MOVQ CX, 48(DX) - MOVQ $0x30644e72e131a029, CX - SBBQ R8, CX - MOVQ CX, 56(DX) - RET - -TEXT ·mulNonResE2(SB), NOSPLIT, $0-16 - MOVQ x+8(FP), R10 - MOVQ 0(R10), AX - MOVQ 8(R10), DX - MOVQ 16(R10), CX - MOVQ 24(R10), BX - ADDQ AX, AX - ADCQ DX, DX - ADCQ CX, CX - ADCQ BX, BX - - // reduce element(AX,DX,CX,BX) using temp registers (R11,R12,R13,R14) - REDUCE(AX,DX,CX,BX,R11,R12,R13,R14) - - ADDQ AX, AX - ADCQ DX, DX - ADCQ CX, CX - ADCQ BX, BX - - // reduce element(AX,DX,CX,BX) using temp registers (R15,R11,R12,R13) - REDUCE(AX,DX,CX,BX,R15,R11,R12,R13) - - ADDQ AX, AX - ADCQ DX, DX - ADCQ CX, CX - ADCQ BX, BX - - // reduce element(AX,DX,CX,BX) using temp registers (R14,R15,R11,R12) - REDUCE(AX,DX,CX,BX,R14,R15,R11,R12) - - ADDQ 0(R10), AX - ADCQ 8(R10), DX - ADCQ 16(R10), CX - ADCQ 24(R10), BX - - // reduce element(AX,DX,CX,BX) using temp registers (R13,R14,R15,R11) - REDUCE(AX,DX,CX,BX,R13,R14,R15,R11) - - MOVQ 32(R10), SI - MOVQ 40(R10), DI - MOVQ 48(R10), R8 - MOVQ 56(R10), R9 - XORQ R12, R12 - SUBQ SI, AX - SBBQ DI, DX - SBBQ R8, CX - SBBQ R9, BX - MOVQ $0x3c208c16d87cfd47, R13 - MOVQ $0x97816a916871ca8d, R14 - MOVQ $0xb85045b68181585d, R15 - MOVQ $0x30644e72e131a029, R11 - CMOVQCC R12, R13 - CMOVQCC R12, R14 - CMOVQCC R12, R15 - CMOVQCC R12, R11 - ADDQ R13, AX - ADCQ R14, DX - ADCQ R15, CX - ADCQ R11, BX - ADDQ SI, SI - ADCQ DI, DI - ADCQ R8, R8 - ADCQ R9, R9 - - // reduce element(SI,DI,R8,R9) using temp registers (R13,R14,R15,R11) - REDUCE(SI,DI,R8,R9,R13,R14,R15,R11) - - ADDQ SI, SI - ADCQ DI, DI - ADCQ R8, R8 - ADCQ R9, R9 - - // reduce element(SI,DI,R8,R9) using temp registers (R12,R13,R14,R15) - REDUCE(SI,DI,R8,R9,R12,R13,R14,R15) - - ADDQ SI, SI - ADCQ DI, DI - ADCQ R8, R8 - ADCQ R9, R9 - - // reduce element(SI,DI,R8,R9) using temp registers (R11,R12,R13,R14) - REDUCE(SI,DI,R8,R9,R11,R12,R13,R14) - - ADDQ 32(R10), SI - ADCQ 40(R10), DI - ADCQ 48(R10), R8 - ADCQ 56(R10), R9 - - // reduce element(SI,DI,R8,R9) using temp registers (R15,R11,R12,R13) - REDUCE(SI,DI,R8,R9,R15,R11,R12,R13) - - ADDQ 0(R10), SI - ADCQ 8(R10), DI - ADCQ 16(R10), R8 - ADCQ 24(R10), R9 - - // reduce element(SI,DI,R8,R9) using temp registers (R14,R15,R11,R12) - REDUCE(SI,DI,R8,R9,R14,R15,R11,R12) - - MOVQ res+0(FP), R10 - MOVQ AX, 0(R10) - MOVQ DX, 8(R10) - MOVQ CX, 16(R10) - MOVQ BX, 24(R10) - MOVQ SI, 32(R10) - MOVQ DI, 40(R10) - MOVQ R8, 48(R10) - MOVQ R9, 56(R10) - RET - -TEXT ·mulAdxE2(SB), $64-24 - NO_LOCAL_POINTERS - - // var a, b, c fp.Element - // a.Add(&x.A0, &x.A1) - // b.Add(&y.A0, &y.A1) - // a.Mul(&a, &b) - // b.Mul(&x.A0, &y.A0) - // c.Mul(&x.A1, &y.A1) - // z.A1.Sub(&a, &b).Sub(&z.A1, &c) - // z.A0.Sub(&b, &c) - - MOVQ x+8(FP), AX - MOVQ y+16(FP), DX - MOVQ 32(AX), R14 - MOVQ 40(AX), R15 - MOVQ 48(AX), CX - MOVQ 56(AX), BX - MOVQ 32(DX), SI - MOVQ 40(DX), DI - MOVQ 48(DX), R8 - MOVQ 56(DX), R9 - - // mul (R14,R15,CX,BX) with (SI,DI,R8,R9) into (R10,R11,R12,R13) - MUL() - - // reduce element(R10,R11,R12,R13) using temp registers (SI,DI,R8,R9) - REDUCE(R10,R11,R12,R13,SI,DI,R8,R9) - - MOVQ R10, s4-40(SP) - MOVQ R11, s5-48(SP) - MOVQ R12, s6-56(SP) - MOVQ R13, s7-64(SP) - MOVQ x+8(FP), AX - MOVQ y+16(FP), DX - ADDQ 0(AX), R14 - ADCQ 8(AX), R15 - ADCQ 16(AX), CX - ADCQ 24(AX), BX - MOVQ 0(DX), SI - MOVQ 8(DX), DI - MOVQ 16(DX), R8 - MOVQ 24(DX), R9 - ADDQ 32(DX), SI - ADCQ 40(DX), DI - ADCQ 48(DX), R8 - ADCQ 56(DX), R9 - - // mul (R14,R15,CX,BX) with (SI,DI,R8,R9) into (R10,R11,R12,R13) - MUL() - - // reduce element(R10,R11,R12,R13) using temp registers (SI,DI,R8,R9) - REDUCE(R10,R11,R12,R13,SI,DI,R8,R9) - - MOVQ R10, s0-8(SP) - MOVQ R11, s1-16(SP) - MOVQ R12, s2-24(SP) - MOVQ R13, s3-32(SP) - MOVQ x+8(FP), AX - MOVQ y+16(FP), DX - MOVQ 0(AX), R14 - MOVQ 8(AX), R15 - MOVQ 16(AX), CX - MOVQ 24(AX), BX - MOVQ 0(DX), SI - MOVQ 8(DX), DI - MOVQ 16(DX), R8 - MOVQ 24(DX), R9 - - // mul (R14,R15,CX,BX) with (SI,DI,R8,R9) into (R10,R11,R12,R13) - MUL() - - // reduce element(R10,R11,R12,R13) using temp registers (SI,DI,R8,R9) - REDUCE(R10,R11,R12,R13,SI,DI,R8,R9) - - XORQ DX, DX - MOVQ s0-8(SP), R14 - MOVQ s1-16(SP), R15 - MOVQ s2-24(SP), CX - MOVQ s3-32(SP), BX - SUBQ R10, R14 - SBBQ R11, R15 - SBBQ R12, CX - SBBQ R13, BX - MOVQ $0x3c208c16d87cfd47, SI - MOVQ $0x97816a916871ca8d, DI - MOVQ $0xb85045b68181585d, R8 - MOVQ $0x30644e72e131a029, R9 - CMOVQCC DX, SI - CMOVQCC DX, DI - CMOVQCC DX, R8 - CMOVQCC DX, R9 - ADDQ SI, R14 - ADCQ DI, R15 - ADCQ R8, CX - ADCQ R9, BX - SUBQ s4-40(SP), R14 - SBBQ s5-48(SP), R15 - SBBQ s6-56(SP), CX - SBBQ s7-64(SP), BX - MOVQ $0x3c208c16d87cfd47, SI - MOVQ $0x97816a916871ca8d, DI - MOVQ $0xb85045b68181585d, R8 - MOVQ $0x30644e72e131a029, R9 - CMOVQCC DX, SI - CMOVQCC DX, DI - CMOVQCC DX, R8 - CMOVQCC DX, R9 - ADDQ SI, R14 - ADCQ DI, R15 - ADCQ R8, CX - ADCQ R9, BX - MOVQ res+0(FP), AX - MOVQ R14, 32(AX) - MOVQ R15, 40(AX) - MOVQ CX, 48(AX) - MOVQ BX, 56(AX) - MOVQ s4-40(SP), SI - MOVQ s5-48(SP), DI - MOVQ s6-56(SP), R8 - MOVQ s7-64(SP), R9 - SUBQ SI, R10 - SBBQ DI, R11 - SBBQ R8, R12 - SBBQ R9, R13 - MOVQ $0x3c208c16d87cfd47, R14 - MOVQ $0x97816a916871ca8d, R15 - MOVQ $0xb85045b68181585d, CX - MOVQ $0x30644e72e131a029, BX - CMOVQCC DX, R14 - CMOVQCC DX, R15 - CMOVQCC DX, CX - CMOVQCC DX, BX - ADDQ R14, R10 - ADCQ R15, R11 - ADCQ CX, R12 - ADCQ BX, R13 - MOVQ R10, 0(AX) - MOVQ R11, 8(AX) - MOVQ R12, 16(AX) - MOVQ R13, 24(AX) - RET - -TEXT ·squareAdxE2(SB), NOSPLIT, $0-16 - NO_LOCAL_POINTERS - - // z.A0 = (x.A0 + x.A1) * (x.A0 - x.A1) - // z.A1 = 2 * x.A0 * x.A1 - - // 2 * x.A0 * x.A1 - MOVQ x+8(FP), AX - - // x.A0[0] -> SI - // x.A0[1] -> DI - // x.A0[2] -> R8 - // x.A0[3] -> R9 - MOVQ 0(AX), SI - MOVQ 8(AX), DI - MOVQ 16(AX), R8 - MOVQ 24(AX), R9 - - // 2 * x.A1[0] -> R14 - // 2 * x.A1[1] -> R15 - // 2 * x.A1[2] -> CX - // 2 * x.A1[3] -> BX - MOVQ 32(AX), R14 - MOVQ 40(AX), R15 - MOVQ 48(AX), CX - MOVQ 56(AX), BX - ADDQ R14, R14 - ADCQ R15, R15 - ADCQ CX, CX - ADCQ BX, BX - - // mul (R14,R15,CX,BX) with (SI,DI,R8,R9) into (R10,R11,R12,R13) - MUL() - - // reduce element(R10,R11,R12,R13) using temp registers (R14,R15,CX,BX) - REDUCE(R10,R11,R12,R13,R14,R15,CX,BX) - - MOVQ x+8(FP), AX - - // x.A1[0] -> R14 - // x.A1[1] -> R15 - // x.A1[2] -> CX - // x.A1[3] -> BX - MOVQ 32(AX), R14 - MOVQ 40(AX), R15 - MOVQ 48(AX), CX - MOVQ 56(AX), BX - MOVQ res+0(FP), DX - MOVQ R10, 32(DX) - MOVQ R11, 40(DX) - MOVQ R12, 48(DX) - MOVQ R13, 56(DX) - MOVQ R14, R10 - MOVQ R15, R11 - MOVQ CX, R12 - MOVQ BX, R13 - - // Add(&x.A0, &x.A1) - ADDQ SI, R14 - ADCQ DI, R15 - ADCQ R8, CX - ADCQ R9, BX - XORQ BP, BP - - // Sub(&x.A0, &x.A1) - SUBQ R10, SI - SBBQ R11, DI - SBBQ R12, R8 - SBBQ R13, R9 - MOVQ $0x3c208c16d87cfd47, R10 - MOVQ $0x97816a916871ca8d, R11 - MOVQ $0xb85045b68181585d, R12 - MOVQ $0x30644e72e131a029, R13 - CMOVQCC BP, R10 - CMOVQCC BP, R11 - CMOVQCC BP, R12 - CMOVQCC BP, R13 - ADDQ R10, SI - ADCQ R11, DI - ADCQ R12, R8 - ADCQ R13, R9 - - // mul (R14,R15,CX,BX) with (SI,DI,R8,R9) into (R10,R11,R12,R13) - MUL() - - // reduce element(R10,R11,R12,R13) using temp registers (R14,R15,CX,BX) - REDUCE(R10,R11,R12,R13,R14,R15,CX,BX) - - MOVQ res+0(FP), AX - MOVQ R10, 0(AX) - MOVQ R11, 8(AX) - MOVQ R12, 16(AX) - MOVQ R13, 24(AX) - RET diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.go index 7f5b3d3f5e3..259609bd813 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,20 +16,6 @@ package fptower -// q (modulus) -var qE2 = [4]uint64{ - 4332616871279656263, - 10917124144477883021, - 13281191951274694749, - 3486998266802970665, -} - -// q'[0], see montgommery multiplication algorithm -var ( - qE2Inv0 uint64 = 9786893198990664585 - _ = qE2Inv0 // used in asm -) - //go:noescape func addE2(res, x, y *E2) diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.s b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.s index d0c8e8a3d9c..43ffb7f16c8 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.s +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_amd64.s @@ -1,5 +1,3 @@ -// +build !amd64_adx - // Copyright 2020 ConsenSys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_bn254.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_bn254.go index 0a120c4e687..87ab9d1caff 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_bn254.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_bn254.go @@ -19,21 +19,19 @@ import ( ) // declaring nonResInverse as global makes MulByNonResInv inlinable -var nonResInverse E2 - -func init() { - nonResInverse.A0 = fp.Element{ +var nonResInverse E2 = E2{ + A0: fp.Element{ 10477841894441615122, 7327163185667482322, 3635199979766503006, 3215324977242306624, - } - nonResInverse.A1 = fp.Element{ + }, + A1: fp.Element{ 7515750141297360845, 14746352163864140223, 11319968037783994424, 30185921062296004, - } + }, } // mulGenericE2 sets z to the E2-product of x,y, returns z @@ -46,13 +44,13 @@ func mulGenericE2(z, x, y *E2) { b.Mul(&x.A0, &y.A0) c.Mul(&x.A1, &y.A1) z.A1.Sub(&a, &b).Sub(&z.A1, &c) - z.A0.Sub(&b, &c) //z.A0.MulByNonResidue(&c).Add(&z.A0, &b) + z.A0.Sub(&b, &c) // z.A0.MulByNonResidue(&c).Add(&z.A0, &b) } // squareGenericE2 sets z to the E2-product of x,x returns z // note: do not rename, this is referenced in the x86 assembly impl -func squareGenericE2(z, x *E2) *E2 { - // algo 22 https://eprint.iacr.org/2010/354.pdf +func squareGenericE2(z, x *E2) { + // adapted from algo 22 https://eprint.iacr.org/2010/354.pdf var a, b fp.Element a.Add(&x.A0, &x.A1) b.Sub(&x.A0, &x.A1) @@ -60,7 +58,6 @@ func squareGenericE2(z, x *E2) *E2 { b.Mul(&x.A0, &x.A1).Double(&b) z.A0.Set(&a) z.A1.Set(&b) - return z } // MulByNonResidueInv multiplies a E2 by (9,1)^{-1} @@ -70,6 +67,8 @@ func (z *E2) MulByNonResidueInv(x *E2) *E2 { } // Inverse sets z to the E2-inverse of x, returns z +// +// if x == 0, sets and returns z = x func (z *E2) Inverse(x *E2) *E2 { // Algorithm 8 from https://eprint.iacr.org/2010/354.pdf var t0, t1 fp.Element @@ -90,3 +89,14 @@ func (z *E2) norm(x *fp.Element) { tmp.Square(&z.A1) x.Add(x, &tmp) } + +// MulBybTwistCurveCoeff multiplies by 3/(9,1) +func (z *E2) MulBybTwistCurveCoeff(x *E2) *E2 { + + var res E2 + res.MulByNonResidueInv(x) + z.Double(&res). + Add(&res, z) + + return z +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_fallback.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_fallback.go index 0ce4d833347..6fe47c4111b 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_fallback.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e2_fallback.go @@ -1,7 +1,7 @@ //go:build !amd64 // +build !amd64 -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e6.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e6.go index adc33ceefd5..128007df278 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e6.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/e6.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ type E6 struct { B0, B1, B2 E2 } -// Equal returns true if z equals x, fasle otherwise +// Equal returns true if z equals x, false otherwise func (z *E6) Equal(x *E6) bool { return z.B0.Equal(&x.B0) && z.B1.Equal(&x.B1) && z.B2.Equal(&x.B2) } @@ -63,20 +63,13 @@ func (z *E6) SetRandom() (*E6, error) { return z, nil } -// ToMont converts to Mont form -func (z *E6) ToMont() *E6 { - z.B0.ToMont() - z.B1.ToMont() - z.B2.ToMont() - return z +// IsZero returns true if the two elements are equal, false otherwise +func (z *E6) IsZero() bool { + return z.B0.IsZero() && z.B1.IsZero() && z.B2.IsZero() } -// FromMont converts from Mont form -func (z *E6) FromMont() *E6 { - z.B0.FromMont() - z.B1.FromMont() - z.B2.FromMont() - return z +func (z *E6) IsOne() bool { + return z.B0.IsOne() && z.B1.IsZero() && z.B2.IsZero() } // Add adds two elements of E6 @@ -133,6 +126,34 @@ func (z *E6) MulByE2(x *E6, y *E2) *E6 { return z } +// MulBy12 multiplication by sparse element (0,b1,b2) +func (x *E6) MulBy12(b1, b2 *E2) *E6 { + var t1, t2, c0, tmp, c1, c2 E2 + t1.Mul(&x.B1, b1) + t2.Mul(&x.B2, b2) + c0.Add(&x.B1, &x.B2) + tmp.Add(b1, b2) + c0.Mul(&c0, &tmp) + c0.Sub(&c0, &t1) + c0.Sub(&c0, &t2) + c0.MulByNonResidue(&c0) + c1.Add(&x.B0, &x.B1) + c1.Mul(&c1, b1) + c1.Sub(&c1, &t1) + tmp.MulByNonResidue(&t2) + c1.Add(&c1, &tmp) + tmp.Add(&x.B0, &x.B2) + c2.Mul(b2, &tmp) + c2.Sub(&c2, &t2) + c2.Add(&c2, &t1) + + x.B0 = c0 + x.B1 = c1 + x.B2 = c2 + + return x +} + // MulBy01 multiplication by sparse element (c0,c1,0) func (z *E6) MulBy01(c0, c1 *E2) *E6 { @@ -237,6 +258,8 @@ func (z *E6) Square(x *E6) *E6 { } // Inverse an element in E6 +// +// if x == 0, sets and returns z = x func (z *E6) Inverse(x *E6) *E6 { // Algorithm 17 from https://eprint.iacr.org/2010/354.pdf // step 9 is wrong in the paper it's t1-t4 @@ -262,3 +285,55 @@ func (z *E6) Inverse(x *E6) *E6 { return z } + +// BatchInvertE6 returns a new slice with every element inverted. +// Uses Montgomery batch inversion trick +// +// if a[i] == 0, returns result[i] = a[i] +func BatchInvertE6(a []E6) []E6 { + res := make([]E6, len(a)) + if len(a) == 0 { + return res + } + + zeroes := make([]bool, len(a)) + var accumulator E6 + accumulator.SetOne() + + for i := 0; i < len(a); i++ { + if a[i].IsZero() { + zeroes[i] = true + continue + } + res[i].Set(&accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + accumulator.Inverse(&accumulator) + + for i := len(a) - 1; i >= 0; i-- { + if zeroes[i] { + continue + } + res[i].Mul(&res[i], &accumulator) + accumulator.Mul(&accumulator, &a[i]) + } + + return res +} + +func (z *E6) Select(cond int, caseZ *E6, caseNz *E6) *E6 { + //Might be able to save a nanosecond or two by an aggregate implementation + + z.B0.Select(cond, &caseZ.B0, &caseNz.B0) + z.B1.Select(cond, &caseZ.B1, &caseNz.B1) + z.B2.Select(cond, &caseZ.B2, &caseNz.B2) + + return z +} + +func (z *E6) Div(x *E6, y *E6) *E6 { + var r E6 + r.Inverse(y).Mul(x, &r) + return z.Set(&r) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/parameters.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/parameters.go new file mode 100644 index 00000000000..3859aeac76f --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower/parameters.go @@ -0,0 +1,33 @@ +// Copyright 2020 ConsenSys AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fptower + +import ( + "math/big" + + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +// generator of the curve +var xGen big.Int + +var glvBasis ecc.Lattice + +func init() { + xGen.SetString("147946756881789318990833708069417712966", 10) + _r := fr.Modulus() + ecc.PrecomputeLattice(_r, &xGen, &glvBasis) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/marshal.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/marshal.go index 08194ed7930..d4a6f6eea99 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/marshal.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/marshal.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -44,6 +44,11 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ( + ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + ErrInvalidEncoding = errors.New("invalid point encoding") +) + // Encoder writes bn254 object values to an output stream type Encoder struct { w io.Writer @@ -74,28 +79,64 @@ func NewDecoder(r io.Reader, options ...func(*Decoder)) *Decoder { // type must be *uint64, *fr.Element, *fp.Element, *G1Affine, *G2Affine, *[]G1Affine or *[]G2Affine func (dec *Decoder) Decode(v interface{}) (err error) { rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { + if v == nil || rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { return errors.New("bn254 decoder: unsupported type, need pointer") } // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap // in particular, careful attention must be given to usage of Bytes() method on Elements and Points - // that return an array (not a slice) of bytes. Using this is beneficial to minimize memallocs + // that return an array (not a slice) of bytes. Using this is beneficial to minimize memory allocations // in very large (de)serialization upstream in gnark. - // (but detrimental to code lisibility here) - // TODO double check memory usage and factorize this + // (but detrimental to code readability here) + + var read64 int64 + if vf, ok := v.(io.ReaderFrom); ok { + read64, err = vf.ReadFrom(dec.r) + dec.n += read64 + return + } var buf [SizeOfG2AffineUncompressed]byte var read int + var sliceLen uint32 switch t := v.(type) { + case *[][]uint64: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + *t = make([][]uint64, sliceLen) + + for i := range *t { + if sliceLen, err = dec.readUint32(); err != nil { + return + } + (*t)[i] = make([]uint64, sliceLen) + for j := range (*t)[i] { + if (*t)[i][j], err = dec.readUint64(); err != nil { + return + } + } + } + return + case *[]uint64: + if sliceLen, err = dec.readUint32(); err != nil { + return + } + *t = make([]uint64, sliceLen) + for i := range *t { + if (*t)[i], err = dec.readUint64(); err != nil { + return + } + } + return case *fr.Element: read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) dec.n += int64(read) if err != nil { return } - t.SetBytes(buf[:fr.Bytes]) + err = t.SetBytesCanonical(buf[:fr.Bytes]) return case *fp.Element: read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) @@ -103,44 +144,26 @@ func (dec *Decoder) Decode(v interface{}) (err error) { if err != nil { return } - t.SetBytes(buf[:fp.Bytes]) + err = t.SetBytesCanonical(buf[:fp.Bytes]) return case *[]fr.Element: - var sliceLen uint32 - sliceLen, err = dec.readUint32() - if err != nil { - return - } - if len(*t) != int(sliceLen) { - *t = make([]fr.Element, sliceLen) - } - - for i := 0; i < len(*t); i++ { - read, err = io.ReadFull(dec.r, buf[:fr.Bytes]) - dec.n += int64(read) - if err != nil { - return - } - (*t)[i].SetBytes(buf[:fr.Bytes]) - } + read64, err = (*fr.Vector)(t).ReadFrom(dec.r) + dec.n += read64 return case *[]fp.Element: - var sliceLen uint32 - sliceLen, err = dec.readUint32() - if err != nil { + read64, err = (*fp.Vector)(t).ReadFrom(dec.r) + dec.n += read64 + return + case *[][]fr.Element: + if sliceLen, err = dec.readUint32(); err != nil { return } if len(*t) != int(sliceLen) { - *t = make([]fp.Element, sliceLen) + *t = make([][]fr.Element, sliceLen) } - - for i := 0; i < len(*t); i++ { - read, err = io.ReadFull(dec.r, buf[:fp.Bytes]) - dec.n += int64(read) - if err != nil { - return - } - (*t)[i].SetBytes(buf[:fp.Bytes]) + for i := range *t { + read64, err = (*fr.Vector)(&(*t)[i]).ReadFrom(dec.r) + dec.n += read64 } return case *G1Affine: @@ -151,6 +174,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return } nbBytes := SizeOfG1AffineCompressed + // most significant byte contains metadata if !isCompressed(buf[0]) { nbBytes = SizeOfG1AffineUncompressed @@ -171,6 +195,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return } nbBytes := SizeOfG2AffineCompressed + // most significant byte contains metadata if !isCompressed(buf[0]) { nbBytes = SizeOfG2AffineUncompressed @@ -184,12 +209,11 @@ func (dec *Decoder) Decode(v interface{}) (err error) { _, err = t.setBytes(buf[:nbBytes], dec.subGroupCheck) return case *[]G1Affine: - var sliceLen uint32 sliceLen, err = dec.readUint32() if err != nil { return } - if len(*t) != int(sliceLen) { + if len(*t) != int(sliceLen) || *t == nil { *t = make([]G1Affine, sliceLen) } compressed := make([]bool, sliceLen) @@ -202,6 +226,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return } nbBytes := SizeOfG1AffineCompressed + // most significant byte contains metadata if !isCompressed(buf[0]) { nbBytes = SizeOfG1AffineUncompressed @@ -216,7 +241,11 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return } } else { - compressed[i] = !((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])) + var r bool + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { + return + } + compressed[i] = !r } } var nbErrs uint64 @@ -239,7 +268,6 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return nil case *[]G2Affine: - var sliceLen uint32 sliceLen, err = dec.readUint32() if err != nil { return @@ -257,6 +285,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return } nbBytes := SizeOfG2AffineCompressed + // most significant byte contains metadata if !isCompressed(buf[0]) { nbBytes = SizeOfG2AffineUncompressed @@ -271,7 +300,11 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return } } else { - compressed[i] = !((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])) + var r bool + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { + return + } + compressed[i] = !r } } var nbErrs uint64 @@ -323,6 +356,18 @@ func (dec *Decoder) readUint32() (r uint32, err error) { return } +func (dec *Decoder) readUint64() (r uint64, err error) { + var read int + var buf [8]byte + read, err = io.ReadFull(dec.r, buf[:]) + dec.n += int64(read) + if err != nil { + return + } + r = binary.BigEndian.Uint64(buf[:]) + return +} + func isCompressed(msb byte) bool { mData := msb & mMask return !(mData == mUncompressed) @@ -375,13 +420,41 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap - // TODO double check memory usage and factorize this + + var written64 int64 + if vw, ok := v.(io.WriterTo); ok { + written64, err = vw.WriteTo(enc.w) + enc.n += written64 + return + } var written int + switch t := v.(type) { + case []uint64: + return enc.writeUint64Slice(t) + case [][]uint64: + return enc.writeUint64SliceSlice(t) case *fr.Element: buf := t.Bytes() written, err = enc.w.Write(buf[:]) @@ -402,41 +475,33 @@ func (enc *Encoder) encode(v interface{}) (err error) { written, err = enc.w.Write(buf[:]) enc.n += int64(written) return + case fr.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case fp.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return case []fr.Element: - // write slice length - err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) - if err != nil { - return - } - enc.n += 4 - var buf [fr.Bytes]byte - for i := 0; i < len(t); i++ { - buf = t[i].Bytes() - written, err = enc.w.Write(buf[:]) - enc.n += int64(written) - if err != nil { - return - } - } - return nil + written64, err = (*fr.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return case []fp.Element: + written64, err = (*fp.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case [][]fr.Element: // write slice length - err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) - if err != nil { + if err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))); err != nil { return } enc.n += 4 - var buf [fp.Bytes]byte - for i := 0; i < len(t); i++ { - buf = t[i].Bytes() - written, err = enc.w.Write(buf[:]) - enc.n += int64(written) - if err != nil { - return - } + for i := range t { + written64, err = (*fr.Vector)(&t[i]).WriteTo(enc.w) + enc.n += written64 } - return nil - + return case []G1Affine: // write slice length err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) @@ -487,12 +552,27 @@ func (enc *Encoder) encode(v interface{}) (err error) { } func (enc *Encoder) encodeRaw(v interface{}) (err error) { + rv := reflect.ValueOf(v) + if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { + return errors.New(" encoder: can't encode ") + } // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap - // TODO double check memory usage and factorize this + + var written64 int64 + if vw, ok := v.(io.WriterTo); ok { + written64, err = vw.WriteTo(enc.w) + enc.n += written64 + return + } var written int + switch t := v.(type) { + case []uint64: + return enc.writeUint64Slice(t) + case [][]uint64: + return enc.writeUint64SliceSlice(t) case *fr.Element: buf := t.Bytes() written, err = enc.w.Write(buf[:]) @@ -513,41 +593,33 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { written, err = enc.w.Write(buf[:]) enc.n += int64(written) return + case fr.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return + case fp.Vector: + written64, err = t.WriteTo(enc.w) + enc.n += written64 + return case []fr.Element: - // write slice length - err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) - if err != nil { - return - } - enc.n += 4 - var buf [fr.Bytes]byte - for i := 0; i < len(t); i++ { - buf = t[i].Bytes() - written, err = enc.w.Write(buf[:]) - enc.n += int64(written) - if err != nil { - return - } - } - return nil + written64, err = (*fr.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return case []fp.Element: + written64, err = (*fp.Vector)(&t).WriteTo(enc.w) + enc.n += written64 + return + case [][]fr.Element: // write slice length - err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) - if err != nil { + if err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))); err != nil { return } enc.n += 4 - var buf [fp.Bytes]byte - for i := 0; i < len(t); i++ { - buf = t[i].Bytes() - written, err = enc.w.Write(buf[:]) - enc.n += int64(written) - if err != nil { - return - } + for i := range t { + written64, err = (*fr.Vector)(&t[i]).WriteTo(enc.w) + enc.n += written64 } - return nil - + return case []G1Affine: // write slice length err = binary.Write(enc.w, binary.BigEndian, uint32(len(t))) @@ -597,6 +669,51 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { } } +func (enc *Encoder) writeUint64Slice(t []uint64) (err error) { + if err = enc.writeUint32(uint32(len(t))); err != nil { + return + } + for i := range t { + if err = enc.writeUint64(t[i]); err != nil { + return + } + } + return nil +} + +func (enc *Encoder) writeUint64SliceSlice(t [][]uint64) (err error) { + if err = enc.writeUint32(uint32(len(t))); err != nil { + return + } + for i := range t { + if err = enc.writeUint32(uint32(len(t[i]))); err != nil { + return + } + for j := range t[i] { + if err = enc.writeUint64(t[i][j]); err != nil { + return + } + } + } + return nil +} + +func (enc *Encoder) writeUint64(a uint64) error { + var buff [64 / 8]byte + binary.BigEndian.PutUint64(buff[:], a) + written, err := enc.w.Write(buff[:]) + enc.n += int64(written) + return err +} + +func (enc *Encoder) writeUint32(a uint32) error { + var buff [32 / 8]byte + binary.BigEndian.PutUint32(buff[:], a) + written, err := enc.w.Write(buff[:]) + enc.n += int64(written) + return err +} + // SizeOfG1AffineCompressed represents the size in bytes that a G1Affine need in binary form, compressed const SizeOfG1AffineCompressed = 32 @@ -609,7 +726,7 @@ func (p *G1Affine) Marshal() []byte { return b[:] } -// Unmarshal is an allias to SetBytes() +// Unmarshal is an alias to SetBytes() func (p *G1Affine) Unmarshal(buf []byte) error { _, err := p.SetBytes(buf) return err @@ -618,12 +735,14 @@ func (p *G1Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit // as we have less than 3 bits available in our coordinate, we can't follow BLS12-381 style encoding (ZCash/IETF) +// // we use the 2 most significant bits instead -// 00 -> uncompressed -// 10 -> compressed, use smallest lexicographically square root of Y^2 -// 11 -> compressed, use largest lexicographically square root of Y^2 -// 01 -> compressed infinity point -// the "uncompressed infinity point" will just have 00 (uncompressed) followed by zeroes (infinity = 0,0 in affine coordinates) +// +// 00 -> uncompressed +// 10 -> compressed, use smallest lexicographically square root of Y^2 +// 11 -> compressed, use largest lexicographically square root of Y^2 +// 01 -> compressed infinity point +// the "uncompressed infinity point" will just have 00 (uncompressed) followed by zeroes (infinity = 0,0 in affine coordinates) func (p *G1Affine) Bytes() (res [SizeOfG1AffineCompressed]byte) { // check if p is infinity point @@ -632,9 +751,6 @@ func (p *G1Affine) Bytes() (res [SizeOfG1AffineCompressed]byte) { return } - // tmp is used to convert from montgomery representation to regular - var tmp fp.Element - msbMask := mCompressedSmallest // compressed, we need to know if Y is lexicographically bigger than -Y // if p.Y ">" -p.Y @@ -643,12 +759,7 @@ func (p *G1Affine) Bytes() (res [SizeOfG1AffineCompressed]byte) { } // we store X and mask the most significant word with our metadata mask - tmp = p.X - tmp.FromMont() - binary.BigEndian.PutUint64(res[24:32], tmp[0]) - binary.BigEndian.PutUint64(res[16:24], tmp[1]) - binary.BigEndian.PutUint64(res[8:16], tmp[2]) - binary.BigEndian.PutUint64(res[0:8], tmp[3]) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) res[0] |= msbMask @@ -667,25 +778,12 @@ func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { return } - // tmp is used to convert from montgomery representation to regular - var tmp fp.Element - // not compressed // we store the Y coordinate - tmp = p.Y - tmp.FromMont() - binary.BigEndian.PutUint64(res[56:64], tmp[0]) - binary.BigEndian.PutUint64(res[48:56], tmp[1]) - binary.BigEndian.PutUint64(res[40:48], tmp[2]) - binary.BigEndian.PutUint64(res[32:40], tmp[3]) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[32:32+fp.Bytes]), p.Y) // we store X and mask the most significant word with our metadata mask - tmp = p.X - tmp.FromMont() - binary.BigEndian.PutUint64(res[24:32], tmp[0]) - binary.BigEndian.PutUint64(res[16:24], tmp[1]) - binary.BigEndian.PutUint64(res[8:16], tmp[2]) - binary.BigEndian.PutUint64(res[0:8], tmp[3]) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X) res[0] |= mUncompressed @@ -693,10 +791,14 @@ func (p *G1Affine) RawBytes() (res [SizeOfG1AffineUncompressed]byte) { } // SetBytes sets p from binary representation in buf and returns number of consumed bytes +// // bytes in buf must match either RawBytes() or Bytes() output +// // if buf is too short io.ErrShortBuffer is returned +// // if buf contains compressed representation (output from Bytes()) and we're unable to compute -// the Y coordinate (i.e the square root doesn't exist) this function retunrs an error +// the Y coordinate (i.e the square root doesn't exist) this function returns an error +// // this check if the resulting point is on the curve and in the correct subgroup func (p *G1Affine) SetBytes(buf []byte) (int, error) { return p.setBytes(buf, true) @@ -717,8 +819,11 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil @@ -727,8 +832,12 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { // uncompressed point if mData == mUncompressed { // read X and Y coordinates - p.X.SetBytes(buf[:fp.Bytes]) - p.Y.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + if err := p.X.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.Y.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } // subgroup check if subGroupCheck && !p.IsInSubGroup() { @@ -748,7 +857,9 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { bufX[0] &= ^mMask // read X coordinate - p.X.SetBytes(bufX[:fp.Bytes]) + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return 0, err + } var YSquared, Y fp.Element @@ -822,16 +933,19 @@ func (p *G1Affine) unsafeComputeY(subGroupCheck bool) error { // assumes buf[:8] mask is set to compressed // returns true if point is infinity and need no further processing // it sets X coordinate and uses Y for scratch space to store decompression metadata -func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool) { +func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err error) { // read the most significant byte mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true - return + return isInfinity, nil } // we need to copy the input buffer (to keep this method thread safe) @@ -840,12 +954,14 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool) { bufX[0] &= ^mMask // read X coordinate - p.X.SetBytes(bufX[:fp.Bytes]) + if err := p.X.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return false, err + } // store mData in p.Y[0] p.Y[0] = uint64(mData) // recomputing Y will be done asynchronously - return + return isInfinity, nil } // SizeOfG2AffineCompressed represents the size in bytes that a G2Affine need in binary form, compressed @@ -860,7 +976,7 @@ func (p *G2Affine) Marshal() []byte { return b[:] } -// Unmarshal is an allias to SetBytes() +// Unmarshal is an alias to SetBytes() func (p *G2Affine) Unmarshal(buf []byte) error { _, err := p.SetBytes(buf) return err @@ -869,12 +985,14 @@ func (p *G2Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit // as we have less than 3 bits available in our coordinate, we can't follow BLS12-381 style encoding (ZCash/IETF) +// // we use the 2 most significant bits instead -// 00 -> uncompressed -// 10 -> compressed, use smallest lexicographically square root of Y^2 -// 11 -> compressed, use largest lexicographically square root of Y^2 -// 01 -> compressed infinity point -// the "uncompressed infinity point" will just have 00 (uncompressed) followed by zeroes (infinity = 0,0 in affine coordinates) +// +// 00 -> uncompressed +// 10 -> compressed, use smallest lexicographically square root of Y^2 +// 11 -> compressed, use largest lexicographically square root of Y^2 +// 01 -> compressed infinity point +// the "uncompressed infinity point" will just have 00 (uncompressed) followed by zeroes (infinity = 0,0 in affine coordinates) func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { // check if p is infinity point @@ -883,9 +1001,6 @@ func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { return } - // tmp is used to convert from montgomery representation to regular - var tmp fp.Element - msbMask := mCompressedSmallest // compressed, we need to know if Y is lexicographically bigger than -Y // if p.Y ">" -p.Y @@ -894,20 +1009,9 @@ func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { } // we store X and mask the most significant word with our metadata mask - // p.X.A1 | p.X.A0 - tmp = p.X.A0 - tmp.FromMont() - binary.BigEndian.PutUint64(res[56:64], tmp[0]) - binary.BigEndian.PutUint64(res[48:56], tmp[1]) - binary.BigEndian.PutUint64(res[40:48], tmp[2]) - binary.BigEndian.PutUint64(res[32:40], tmp[3]) - - tmp = p.X.A1 - tmp.FromMont() - binary.BigEndian.PutUint64(res[24:32], tmp[0]) - binary.BigEndian.PutUint64(res[16:24], tmp[1]) - binary.BigEndian.PutUint64(res[8:16], tmp[2]) - binary.BigEndian.PutUint64(res[0:8], tmp[3]) + // p.X.A1 | p.X.A0 + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[32:32+fp.Bytes]), p.X.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) res[0] |= msbMask @@ -926,41 +1030,16 @@ func (p *G2Affine) RawBytes() (res [SizeOfG2AffineUncompressed]byte) { return } - // tmp is used to convert from montgomery representation to regular - var tmp fp.Element - // not compressed // we store the Y coordinate // p.Y.A1 | p.Y.A0 - tmp = p.Y.A0 - tmp.FromMont() - binary.BigEndian.PutUint64(res[120:128], tmp[0]) - binary.BigEndian.PutUint64(res[112:120], tmp[1]) - binary.BigEndian.PutUint64(res[104:112], tmp[2]) - binary.BigEndian.PutUint64(res[96:104], tmp[3]) - - tmp = p.Y.A1 - tmp.FromMont() - binary.BigEndian.PutUint64(res[88:96], tmp[0]) - binary.BigEndian.PutUint64(res[80:88], tmp[1]) - binary.BigEndian.PutUint64(res[72:80], tmp[2]) - binary.BigEndian.PutUint64(res[64:72], tmp[3]) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[96:96+fp.Bytes]), p.Y.A0) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[64:64+fp.Bytes]), p.Y.A1) // we store X and mask the most significant word with our metadata mask // p.X.A1 | p.X.A0 - tmp = p.X.A1 - tmp.FromMont() - binary.BigEndian.PutUint64(res[24:32], tmp[0]) - binary.BigEndian.PutUint64(res[16:24], tmp[1]) - binary.BigEndian.PutUint64(res[8:16], tmp[2]) - binary.BigEndian.PutUint64(res[0:8], tmp[3]) - - tmp = p.X.A0 - tmp.FromMont() - binary.BigEndian.PutUint64(res[56:64], tmp[0]) - binary.BigEndian.PutUint64(res[48:56], tmp[1]) - binary.BigEndian.PutUint64(res[40:48], tmp[2]) - binary.BigEndian.PutUint64(res[32:40], tmp[3]) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) + fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[32:32+fp.Bytes]), p.X.A0) res[0] |= mUncompressed @@ -968,10 +1047,14 @@ func (p *G2Affine) RawBytes() (res [SizeOfG2AffineUncompressed]byte) { } // SetBytes sets p from binary representation in buf and returns number of consumed bytes +// // bytes in buf must match either RawBytes() or Bytes() output +// // if buf is too short io.ErrShortBuffer is returned +// // if buf contains compressed representation (output from Bytes()) and we're unable to compute -// the Y coordinate (i.e the square root doesn't exist) this function retunrs an error +// the Y coordinate (i.e the square root doesn't exist) this function returns an error +// // this check if the resulting point is on the curve and in the correct subgroup func (p *G2Affine) SetBytes(buf []byte) (int, error) { return p.setBytes(buf, true) @@ -992,8 +1075,11 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil @@ -1003,11 +1089,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { if mData == mUncompressed { // read X and Y coordinates // p.X.A1 | p.X.A0 - p.X.A1.SetBytes(buf[:fp.Bytes]) - p.X.A0.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + if err := p.X.A1.SetBytesCanonical(buf[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } // p.Y.A1 | p.Y.A0 - p.Y.A1.SetBytes(buf[fp.Bytes*2 : fp.Bytes*3]) - p.Y.A0.SetBytes(buf[fp.Bytes*3 : fp.Bytes*4]) + if err := p.Y.A1.SetBytesCanonical(buf[fp.Bytes*2 : fp.Bytes*3]); err != nil { + return 0, err + } + if err := p.Y.A0.SetBytesCanonical(buf[fp.Bytes*3 : fp.Bytes*4]); err != nil { + return 0, err + } // subgroup check if subGroupCheck && !p.IsInSubGroup() { @@ -1028,8 +1122,12 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { // read X coordinate // p.X.A1 | p.X.A0 - p.X.A1.SetBytes(bufX[:fp.Bytes]) - p.X.A0.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + if err := p.X.A1.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return 0, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return 0, err + } var YSquared, Y fptower.E2 @@ -1105,16 +1203,19 @@ func (p *G2Affine) unsafeComputeY(subGroupCheck bool) error { // assumes buf[:8] mask is set to compressed // returns true if point is infinity and need no further processing // it sets X coordinate and uses Y for scratch space to store decompression metadata -func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool) { +func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err error) { // read the most significant byte mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true - return + return isInfinity, nil } // we need to copy the input buffer (to keep this method thread safe) @@ -1124,12 +1225,16 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool) { // read X coordinate // p.X.A1 | p.X.A0 - p.X.A1.SetBytes(bufX[:fp.Bytes]) - p.X.A0.SetBytes(buf[fp.Bytes : fp.Bytes*2]) + if err := p.X.A1.SetBytesCanonical(bufX[:fp.Bytes]); err != nil { + return false, err + } + if err := p.X.A0.SetBytesCanonical(buf[fp.Bytes : fp.Bytes*2]); err != nil { + return false, err + } // store mData in p.Y.A0[0] p.Y.A0[0] = uint64(mData) // recomputing Y will be done asynchronously - return + return isInfinity, nil } diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp.go index 088fab69145..9d1b71278aa 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp.go @@ -1,4 +1,4 @@ -// Copyright 2020 ConsenSys Software Inc. +// Copyright 2020 Consensys Software Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,144 +25,9 @@ import ( "runtime" ) -// selector stores the index, mask and shifts needed to select bits from a scalar -// it is used during the multiExp algorithm or the batch scalar multiplication -type selector struct { - index uint64 // index in the multi-word scalar to select bits from - mask uint64 // mask (c-bit wide) - shift uint64 // shift needed to get our bits on low positions - - multiWordSelect bool // set to true if we need to select bits from 2 words (case where c doesn't divide 64) - maskHigh uint64 // same than mask, for index+1 - shiftHigh uint64 // same than shift, for index+1 -} - -// partitionScalars compute, for each scalars over c-bit wide windows, nbChunk digits -// if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract -// 2^{c} to the current digit, making it negative. -// negative digits can be processed in a later step as adding -G into the bucket instead of G -// (computing -G is cheap, and this saves us half of the buckets in the MultiExp or BatchScalarMul) -// scalarsMont indicates wheter the provided scalars are in montgomery form -// returns smallValues, which represent the number of scalars which meets the following condition -// 0 < scalar < 2^c (in other words, scalars where only the c-least significant bits are non zero) -func partitionScalars(scalars []fr.Element, c uint64, scalarsMont bool, nbTasks int) ([]fr.Element, int) { - toReturn := make([]fr.Element, len(scalars)) - - // number of c-bit radixes in a scalar - nbChunks := fr.Limbs * 64 / c - if (fr.Limbs*64)%c != 0 { - nbChunks++ - } - - mask := uint64((1 << c) - 1) // low c bits are 1 - msbWindow := uint64(1 << (c - 1)) // msb of the c-bit window - max := int(1 << (c - 1)) // max value we want for our digits - cDivides64 := (64 % c) == 0 // if c doesn't divide 64, we may need to select over multiple words - - // compute offset and word selector / shift to select the right bits of our windows - selectors := make([]selector, nbChunks) - for chunk := uint64(0); chunk < nbChunks; chunk++ { - jc := uint64(chunk * c) - d := selector{} - d.index = jc / 64 - d.shift = jc - (d.index * 64) - d.mask = mask << d.shift - d.multiWordSelect = !cDivides64 && d.shift > (64-c) && d.index < (fr.Limbs-1) - if d.multiWordSelect { - nbBitsHigh := d.shift - uint64(64-c) - d.maskHigh = (1 << nbBitsHigh) - 1 - d.shiftHigh = (c - nbBitsHigh) - } - selectors[chunk] = d - } - - // for each chunk, we could track the number of non-zeros points we will need to process - // this way, if a chunk has more work to do than others, we can spawn off more go routines - // (at the cost of more buckets allocated) - // a simplified approach is to track the small values where only the first word is set - // if this number represent a significant number of points, then we will split first chunk - // processing in the msm in 2, to ensure all go routines finish at ~same time - // /!\ nbTasks is enough as parallel.Execute is not going to spawn more than nbTasks go routine - // if it does, though, this will deadlocK. - chSmallValues := make(chan int, nbTasks) - - parallel.Execute(len(scalars), func(start, end int) { - smallValues := 0 - for i := start; i < end; i++ { - var carry int - - scalar := scalars[i] - if scalarsMont { - scalar.FromMont() - } - if scalar.IsUint64() { - // everything is 0, no need to process this scalar - if scalar[0] == 0 { - continue - } - // low c-bits are 1 in mask - if scalar[0]&mask == scalar[0] { - smallValues++ - } - } - - // for each chunk in the scalar, compute the current digit, and an eventual carry - for chunk := uint64(0); chunk < nbChunks; chunk++ { - s := selectors[chunk] - - // init with carry if any - digit := carry - carry = 0 - - // digit = value of the c-bit window - digit += int((scalar[s.index] & s.mask) >> s.shift) - - if s.multiWordSelect { - // we are selecting bits over 2 words - digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh - } - - // if digit is zero, no impact on result - if digit == 0 { - continue - } - - // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract - // 2^{c} to the current digit, making it negative. - if digit >= max { - digit -= (1 << c) - carry = 1 - } - - var bits uint64 - if digit >= 0 { - bits = uint64(digit) - } else { - bits = uint64(-digit-1) | msbWindow - } - - toReturn[i][s.index] |= (bits << s.shift) - if s.multiWordSelect { - toReturn[i][s.index+1] |= (bits >> s.shiftHigh) - } - - } - } - - chSmallValues <- smallValues - - }, nbTasks) - - // aggregate small values - close(chSmallValues) - smallValues := 0 - for o := range chSmallValues { - smallValues += o - } - return toReturn, smallValues -} - // MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Affine, error) { var _p G1Jac if _, err := _p.MultiExp(points, scalars, config); err != nil { @@ -173,12 +38,15 @@ func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc. } // MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G1Jac, error) { + // TODO @gbotrel replace the ecc.MultiExpConfig by a Option pattern for maintainability. // note: // each of the msmCX method is the same, except for the c constant it declares // duplicating (through template generation) these methods allows to declare the buckets on the stack // the choice of c needs to be improved: - // there is a theoritical value that gives optimal asymptotics + // there is a theoretical value that gives optimal asymptotics // but in practice, other factors come into play, including: // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs @@ -188,7 +56,7 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.Mul // for each msmCX // step 1 // we compute, for each scalars over c-bit wide windows, nbChunk digits - // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract // 2^{c} to the current digit, making it negative. // negative digits will be processed in the next step as adding -G into the bucket instead of G // (computing -G is cheap, and this saves us half of the buckets) @@ -198,7 +66,7 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.Mul // we use jacobian extended formulas here as they are faster than mixed addition // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel // step 3 - // reduce the buckets weigthed sums into our result (msmReduceChunk) + // reduce the buckets weighed sums into our result (msmReduceChunk) // ensure len(points) == len(scalars) nbPoints := len(points) @@ -208,14 +76,16 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.Mul // if nbTasks is not set, use all available CPUs if config.NbTasks <= 0 { - config.NbTasks = runtime.NumCPU() + config.NbTasks = runtime.NumCPU() * 2 + } else if config.NbTasks > 1024 { + return nil, errors.New("invalid config: config.NbTasks > 1024") } // here, we compute the best C for nbPoints // we split recursively until nbChunks(c) >= nbTasks, bestC := func(nbPoints int) uint64 { // implemented msmC methods (the c we use must be in this slice) - implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21} + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} var C uint64 // approximate cost (in group operations) // cost = bits/c * (nbPoints + 2^{c}) @@ -223,121 +93,219 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.Mul // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results min := math.MaxFloat64 for _, c := range implementedCs { - cc := fr.Limbs * 64 * (nbPoints + (1 << (c))) + cc := (fr.Bits + 1) * (nbPoints + (1 << c)) cost := float64(cc) / float64(c) if cost < min { min = cost C = c } } - // empirical, needs to be tuned. - // if C > 16 && nbPoints < 1 << 23 { - // C = 16 - // } return C } - var C uint64 - nbSplits := 1 - nbChunks := 0 - for nbChunks < config.NbTasks { - C = bestC(nbPoints) - nbChunks = int(fr.Limbs * 64 / C) // number of c-bit radixes in a scalar - if (fr.Limbs*64)%C != 0 { - nbChunks++ + C := bestC(nbPoints) + nbChunks := int(computeNbChunks(C)) + + // should we recursively split the msm in half? (see below) + // we want to minimize the execution time of the algorithm; + // splitting the msm will **add** operations, but if it allows to use more CPU, it might be worth it. + + // costFunction returns a metric that represent the "wall time" of the algorithm + costFunction := func(nbTasks, nbCpus, costPerTask int) int { + // cost for the reduction of all tasks (msmReduceChunk) + totalCost := nbTasks + + // cost for the computation of each task (msmProcessChunk) + for nbTasks >= nbCpus { + nbTasks -= nbCpus + totalCost += costPerTask } - nbChunks *= nbSplits - if nbChunks < config.NbTasks { - nbSplits <<= 1 - nbPoints >>= 1 + if nbTasks > 0 { + totalCost += costPerTask } + return totalCost } - // partition the scalars - // note: we do that before the actual chunk processing, as for each c-bit window (starting from LSW) - // if it's larger than 2^{c-1}, we have a carry we need to propagate up to the higher window - var smallValues int - scalars, smallValues = partitionScalars(scalars, C, config.ScalarsMont, config.NbTasks) - - // if we have more than 10% of small values, we split the processing of the first chunk in 2 - // we may want to do that in msmInnerG1Jac , but that would incur a cost of looping through all scalars one more time - splitFirstChunk := (float64(smallValues) / float64(len(scalars))) >= 0.1 - - // we have nbSplits intermediate results that we must sum together. - _p := make([]G1Jac, nbSplits-1) - chDone := make(chan int, nbSplits-1) - for i := 0; i < nbSplits-1; i++ { - start := i * nbPoints - end := start + nbPoints - go func(start, end, i int) { - msmInnerG1Jac(&_p[i], int(C), points[start:end], scalars[start:end], splitFirstChunk) - chDone <- i - }(start, end, i) - } + // costPerTask is the approximate number of group ops per task + costPerTask := func(c uint64, nbPoints int) int { return (nbPoints + int((1 << c))) } - msmInnerG1Jac(p, int(C), points[(nbSplits-1)*nbPoints:], scalars[(nbSplits-1)*nbPoints:], splitFirstChunk) - for i := 0; i < nbSplits-1; i++ { - done := <-chDone - p.AddAssign(&_p[done]) + costPreSplit := costFunction(nbChunks, config.NbTasks, costPerTask(C, nbPoints)) + + cPostSplit := bestC(nbPoints / 2) + nbChunksPostSplit := int(computeNbChunks(cPostSplit)) + costPostSplit := costFunction(nbChunksPostSplit*2, config.NbTasks, costPerTask(cPostSplit, nbPoints/2)) + + // if the cost of the split msm is lower than the cost of the non split msm, we split + if costPostSplit < costPreSplit { + config.NbTasks = int(math.Ceil(float64(config.NbTasks) / 2.0)) + var _p G1Jac + chDone := make(chan struct{}, 1) + go func() { + _p.MultiExp(points[:nbPoints/2], scalars[:nbPoints/2], config) + close(chDone) + }() + p.MultiExp(points[nbPoints/2:], scalars[nbPoints/2:], config) + <-chDone + p.AddAssign(&_p) + return p, nil } - close(chDone) + + // if we don't split, we use the best C we found + _innerMsmG1(p, C, points, scalars, config) + return p, nil } -func msmInnerG1Jac(p *G1Jac, c int, points []G1Affine, scalars []fr.Element, splitFirstChunk bool) { +func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, config ecc.MultiExpConfig) *G1Jac { + // partition the scalars + digits, chunkStats := partitionScalars(scalars, c, config.NbTasks) + + nbChunks := computeNbChunks(c) + + // for each chunk, spawn one go routine that'll loop through all the scalars in the + // corresponding bit-window + // note that buckets is an array allocated on the stack and this is critical for performance + + // each go routine sends its result in chChunks[i] channel + chChunks := make([]chan g1JacExtended, nbChunks) + for i := 0; i < len(chChunks); i++ { + chChunks[i] = make(chan g1JacExtended, 1) + } + + // we use a semaphore to limit the number of go routines running concurrently + // (only if nbTasks < nbCPU) + var sem chan struct{} + if config.NbTasks < runtime.NumCPU() { + // we add nbChunks because if chunk is overweight we split it in two + sem = make(chan struct{}, config.NbTasks+int(nbChunks)) + for i := 0; i < config.NbTasks; i++ { + sem <- struct{}{} + } + defer func() { + close(sem) + }() + } + + // the last chunk may be processed with a different method than the rest, as it could be smaller. + n := len(points) + for j := int(nbChunks - 1); j >= 0; j-- { + processChunk := getChunkProcessorG1(c, chunkStats[j]) + if j == int(nbChunks-1) { + processChunk = getChunkProcessorG1(lastC(c), chunkStats[j]) + } + if chunkStats[j].weight >= 115 { + // we split this in more go routines since this chunk has more work to do than the others. + // else what would happen is this go routine would finish much later than the others. + chSplit := make(chan g1JacExtended, 2) + split := n / 2 + + if sem != nil { + sem <- struct{}{} // add another token to the semaphore, since we split in two. + } + go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split], sem) + go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n], sem) + go func(chunkID int) { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[chunkID] <- s1 + }(j) + continue + } + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) + } + + return msmReduceChunkG1Affine(p, int(c), chChunks[:]) +} +// getChunkProcessorG1 decides, depending on c window size and statistics for the chunk +// to return the best algorithm to process the chunk. +func getChunkProcessorG1(c uint64, stat chunkStat) func(chunkID uint64, chRes chan<- g1JacExtended, c uint64, points []G1Affine, digits []uint16, sem chan struct{}) { switch c { + case 2: + return processChunkG1Jacobian[bucketg1JacExtendedC2] + case 3: + return processChunkG1Jacobian[bucketg1JacExtendedC3] case 4: - p.msmC4(points, scalars, splitFirstChunk) - + return processChunkG1Jacobian[bucketg1JacExtendedC4] case 5: - p.msmC5(points, scalars, splitFirstChunk) - + return processChunkG1Jacobian[bucketg1JacExtendedC5] case 6: - p.msmC6(points, scalars, splitFirstChunk) - + return processChunkG1Jacobian[bucketg1JacExtendedC6] case 7: - p.msmC7(points, scalars, splitFirstChunk) - + return processChunkG1Jacobian[bucketg1JacExtendedC7] case 8: - p.msmC8(points, scalars, splitFirstChunk) - + return processChunkG1Jacobian[bucketg1JacExtendedC8] case 9: - p.msmC9(points, scalars, splitFirstChunk) - + return processChunkG1Jacobian[bucketg1JacExtendedC9] case 10: - p.msmC10(points, scalars, splitFirstChunk) - + const batchSize = 80 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC10] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC10, bucketG1AffineC10, bitSetC10, pG1AffineC10, ppG1AffineC10, qG1AffineC10, cG1AffineC10] case 11: - p.msmC11(points, scalars, splitFirstChunk) - + const batchSize = 150 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC11] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC11, bucketG1AffineC11, bitSetC11, pG1AffineC11, ppG1AffineC11, qG1AffineC11, cG1AffineC11] case 12: - p.msmC12(points, scalars, splitFirstChunk) - + const batchSize = 200 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC12] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC12, bucketG1AffineC12, bitSetC12, pG1AffineC12, ppG1AffineC12, qG1AffineC12, cG1AffineC12] case 13: - p.msmC13(points, scalars, splitFirstChunk) - + const batchSize = 350 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC13] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC13, bucketG1AffineC13, bitSetC13, pG1AffineC13, ppG1AffineC13, qG1AffineC13, cG1AffineC13] case 14: - p.msmC14(points, scalars, splitFirstChunk) - + const batchSize = 400 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC14] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC14, bucketG1AffineC14, bitSetC14, pG1AffineC14, ppG1AffineC14, qG1AffineC14, cG1AffineC14] case 15: - p.msmC15(points, scalars, splitFirstChunk) - + const batchSize = 500 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC15] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC15, bucketG1AffineC15, bitSetC15, pG1AffineC15, ppG1AffineC15, qG1AffineC15, cG1AffineC15] case 16: - p.msmC16(points, scalars, splitFirstChunk) - - case 20: - p.msmC20(points, scalars, splitFirstChunk) - - case 21: - p.msmC21(points, scalars, splitFirstChunk) - - case 22: - p.msmC22(points, scalars, splitFirstChunk) - + const batchSize = 640 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG1Jacobian[bucketg1JacExtendedC16] + } + return processChunkG1BatchAffine[bucketg1JacExtendedC16, bucketG1AffineC16, bitSetC16, pG1AffineC16, ppG1AffineC16, qG1AffineC16, cG1AffineC16] default: - panic("not implemented") + // panic("will not happen c != previous values is not generated by templates") + return processChunkG1Jacobian[bucketg1JacExtendedC16] } } @@ -357,1947 +325,493 @@ func msmReduceChunkG1Affine(p *G1Jac, c int, chChunks []chan g1JacExtended) *G1J return p.unsafeFromJacExtended(&_p) } -func msmProcessChunkG1Affine(chunk uint64, - chRes chan<- g1JacExtended, - buckets []g1JacExtended, - c uint64, - points []G1Affine, - scalars []fr.Element) { - - mask := uint64((1 << c) - 1) // low c bits are 1 - msbWindow := uint64(1 << (c - 1)) - - for i := 0; i < len(buckets); i++ { - buckets[i].setInfinity() - } - - jc := uint64(chunk * c) - s := selector{} - s.index = jc / 64 - s.shift = jc - (s.index * 64) - s.mask = mask << s.shift - s.multiWordSelect = (64%c) != 0 && s.shift > (64-c) && s.index < (fr.Limbs-1) - if s.multiWordSelect { - nbBitsHigh := s.shift - uint64(64-c) - s.maskHigh = (1 << nbBitsHigh) - 1 - s.shiftHigh = (c - nbBitsHigh) +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Affine, error) { + var _p G2Jac + if _, err := _p.MultiExp(points, scalars, config); err != nil { + return nil, err } + p.FromJacobian(&_p) + return p, nil +} - // for each scalars, get the digit corresponding to the chunk we're processing. - for i := 0; i < len(scalars); i++ { - bits := (scalars[i][s.index] & s.mask) >> s.shift - if s.multiWordSelect { - bits += (scalars[i][s.index+1] & s.maskHigh) << s.shiftHigh - } +// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf +// +// This call return an error if len(scalars) != len(points) or if provided config is invalid. +func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Jac, error) { + // TODO @gbotrel replace the ecc.MultiExpConfig by a Option pattern for maintainability. + // note: + // each of the msmCX method is the same, except for the c constant it declares + // duplicating (through template generation) these methods allows to declare the buckets on the stack + // the choice of c needs to be improved: + // there is a theoretical value that gives optimal asymptotics + // but in practice, other factors come into play, including: + // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 + // * number of CPUs + // * cache friendliness (which depends on the host, G1 or G2... ) + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. - if bits == 0 { - continue - } + // for each msmCX + // step 1 + // we compute, for each scalars over c-bit wide windows, nbChunk digits + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + // negative digits will be processed in the next step as adding -G into the bucket instead of G + // (computing -G is cheap, and this saves us half of the buckets) + // step 2 + // buckets are declared on the stack + // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) + // we use jacobian extended formulas here as they are faster than mixed addition + // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel + // step 3 + // reduce the buckets weighed sums into our result (msmReduceChunk) - // if msbWindow bit is set, we need to substract - if bits&msbWindow == 0 { - // add - buckets[bits-1].addMixed(&points[i]) - } else { - // sub - buckets[bits & ^msbWindow].subMixed(&points[i]) - } + // ensure len(points) == len(scalars) + nbPoints := len(points) + if nbPoints != len(scalars) { + return nil, errors.New("len(points) != len(scalars)") } - // reduce buckets into total - // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + // if nbTasks is not set, use all available CPUs + if config.NbTasks <= 0 { + config.NbTasks = runtime.NumCPU() * 2 + } else if config.NbTasks > 1024 { + return nil, errors.New("invalid config: config.NbTasks > 1024") + } - var runningSum, total g1JacExtended - runningSum.setInfinity() - total.setInfinity() - for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { - runningSum.add(&buckets[k]) + // here, we compute the best C for nbPoints + // we split recursively until nbChunks(c) >= nbTasks, + bestC := func(nbPoints int) uint64 { + // implemented msmC methods (the c we use must be in this slice) + implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} + var C uint64 + // approximate cost (in group operations) + // cost = bits/c * (nbPoints + 2^{c}) + // this needs to be verified empirically. + // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results + min := math.MaxFloat64 + for _, c := range implementedCs { + cc := (fr.Bits + 1) * (nbPoints + (1 << c)) + cost := float64(cc) / float64(c) + if cost < min { + min = cost + C = c + } } - total.add(&runningSum) + return C } - chRes <- total - -} + C := bestC(nbPoints) + nbChunks := int(computeNbChunks(C)) -func (p *G1Jac) msmC4(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 4 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) + // should we recursively split the msm in half? (see below) + // we want to minimize the execution time of the algorithm; + // splitting the msm will **add** operations, but if it allows to use more CPU, it might be worth it. - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance + // costFunction returns a metric that represent the "wall time" of the algorithm + costFunction := func(nbTasks, nbCpus, costPerTask int) int { + // cost for the reduction of all tasks (msmReduceChunk) + totalCost := nbTasks - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) + // cost for the computation of each task (msmProcessChunk) + for nbTasks >= nbCpus { + nbTasks -= nbCpus + totalCost += costPerTask + } + if nbTasks > 0 { + totalCost += costPerTask + } + return totalCost } - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } + // costPerTask is the approximate number of group ops per task + costPerTask := func(c uint64, nbPoints int) int { return (nbPoints + int((1 << c))) } - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } + costPreSplit := costFunction(nbChunks, config.NbTasks, costPerTask(C, nbPoints)) - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) + cPostSplit := bestC(nbPoints / 2) + nbChunksPostSplit := int(computeNbChunks(cPostSplit)) + costPostSplit := costFunction(nbChunksPostSplit*2, config.NbTasks, costPerTask(cPostSplit, nbPoints/2)) + + // if the cost of the split msm is lower than the cost of the non split msm, we split + if costPostSplit < costPreSplit { + config.NbTasks = int(math.Ceil(float64(config.NbTasks) / 2.0)) + var _p G2Jac + chDone := make(chan struct{}, 1) go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 + _p.MultiExp(points[:nbPoints/2], scalars[:nbPoints/2], config) + close(chDone) }() + p.MultiExp(points[nbPoints/2:], scalars[nbPoints/2:], config) + <-chDone + p.AddAssign(&_p) + return p, nil } - return msmReduceChunkG1Affine(p, c, chChunks[:]) + // if we don't split, we use the best C we found + _innerMsmG2(p, C, points, scalars, config) + + return p, nil } -func (p *G1Jac) msmC5(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 5 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) +func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) *G2Jac { + // partition the scalars + digits, chunkStats := partitionScalars(scalars, c, config.NbTasks) + + nbChunks := computeNbChunks(c) // for each chunk, spawn one go routine that'll loop through all the scalars in the // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance + // note that buckets is an array allocated on the stack and this is critical for performance // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended + chChunks := make([]chan g2JacExtended, nbChunks) for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) + chChunks[i] = make(chan g2JacExtended, 1) } - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 + // we use a semaphore to limit the number of go routines running concurrently + // (only if nbTasks < nbCPU) + var sem chan struct{} + if config.NbTasks < runtime.NumCPU() { + // we add nbChunks because if chunk is overweight we split it in two + sem = make(chan struct{}, config.NbTasks+int(nbChunks)) + for i := 0; i < config.NbTasks; i++ { + sem <- struct{}{} + } + defer func() { + close(sem) }() } - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC6(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 6 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) + // the last chunk may be processed with a different method than the rest, as it could be smaller. + n := len(points) + for j := int(nbChunks - 1); j >= 0; j-- { + processChunk := getChunkProcessorG2(c, chunkStats[j]) + if j == int(nbChunks-1) { + processChunk = getChunkProcessorG2(lastC(c), chunkStats[j]) + } + if chunkStats[j].weight >= 115 { + // we split this in more go routines since this chunk has more work to do than the others. + // else what would happen is this go routine would finish much later than the others. + chSplit := make(chan g2JacExtended, 2) + split := n / 2 + + if sem != nil { + sem <- struct{}{} // add another token to the semaphore, since we split in two. + } + go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split], sem) + go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n], sem) + go func(chunkID int) { + s1 := <-chSplit + s2 := <-chSplit + close(chSplit) + s1.add(&s2) + chChunks[chunkID] <- s1 + }(j) + continue + } + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) } - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } + return msmReduceChunkG2Affine(p, int(c), chChunks[:]) +} - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } +// getChunkProcessorG2 decides, depending on c window size and statistics for the chunk +// to return the best algorithm to process the chunk. +func getChunkProcessorG2(c uint64, stat chunkStat) func(chunkID uint64, chRes chan<- g2JacExtended, c uint64, points []G2Affine, digits []uint16, sem chan struct{}) { + switch c { - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC7(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 7 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC8(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 8 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC9(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 9 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC10(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 10 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC11(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 11 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC12(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 12 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC13(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 13 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC14(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 14 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC15(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 15 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC16(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 16 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC20(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 20 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC21(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 21 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -func (p *G1Jac) msmC22(points []G1Affine, scalars []fr.Element, splitFirstChunk bool) *G1Jac { - const ( - c = 22 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g1JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g1JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G1Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g1JacExtended - msmProcessChunkG1Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G1Affine, scalars []fr.Element, chChunk chan g1JacExtended) { - var buckets [1 << (c - 1)]g1JacExtended - msmProcessChunkG1Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g1JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG1Affine(p, c, chChunks[:]) -} - -// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf -func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Affine, error) { - var _p G2Jac - if _, err := _p.MultiExp(points, scalars, config); err != nil { - return nil, err - } - p.FromJacobian(&_p) - return p, nil -} - -// MultiExp implements section 4 of https://eprint.iacr.org/2012/549.pdf -func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.MultiExpConfig) (*G2Jac, error) { - // note: - // each of the msmCX method is the same, except for the c constant it declares - // duplicating (through template generation) these methods allows to declare the buckets on the stack - // the choice of c needs to be improved: - // there is a theoritical value that gives optimal asymptotics - // but in practice, other factors come into play, including: - // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 - // * number of CPUs - // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. - - // for each msmCX - // step 1 - // we compute, for each scalars over c-bit wide windows, nbChunk digits - // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and substract - // 2^{c} to the current digit, making it negative. - // negative digits will be processed in the next step as adding -G into the bucket instead of G - // (computing -G is cheap, and this saves us half of the buckets) - // step 2 - // buckets are declared on the stack - // notice that we have 2^{c-1} buckets instead of 2^{c} (see step1) - // we use jacobian extended formulas here as they are faster than mixed addition - // msmProcessChunk places points into buckets base on their selector and return the weighted bucket sum in given channel - // step 3 - // reduce the buckets weigthed sums into our result (msmReduceChunk) - - // ensure len(points) == len(scalars) - nbPoints := len(points) - if nbPoints != len(scalars) { - return nil, errors.New("len(points) != len(scalars)") - } - - // if nbTasks is not set, use all available CPUs - if config.NbTasks <= 0 { - config.NbTasks = runtime.NumCPU() - } - - // here, we compute the best C for nbPoints - // we split recursively until nbChunks(c) >= nbTasks, - bestC := func(nbPoints int) uint64 { - // implemented msmC methods (the c we use must be in this slice) - implementedCs := []uint64{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22} - var C uint64 - // approximate cost (in group operations) - // cost = bits/c * (nbPoints + 2^{c}) - // this needs to be verified empirically. - // for example, on a MBP 2016, for G2 MultiExp > 8M points, hand picking c gives better results - min := math.MaxFloat64 - for _, c := range implementedCs { - cc := fr.Limbs * 64 * (nbPoints + (1 << (c))) - cost := float64(cc) / float64(c) - if cost < min { - min = cost - C = c - } - } - // empirical, needs to be tuned. - // if C > 16 && nbPoints < 1 << 23 { - // C = 16 - // } - return C - } - - var C uint64 - nbSplits := 1 - nbChunks := 0 - for nbChunks < config.NbTasks { - C = bestC(nbPoints) - nbChunks = int(fr.Limbs * 64 / C) // number of c-bit radixes in a scalar - if (fr.Limbs*64)%C != 0 { - nbChunks++ - } - nbChunks *= nbSplits - if nbChunks < config.NbTasks { - nbSplits <<= 1 - nbPoints >>= 1 - } - } - - // partition the scalars - // note: we do that before the actual chunk processing, as for each c-bit window (starting from LSW) - // if it's larger than 2^{c-1}, we have a carry we need to propagate up to the higher window - var smallValues int - scalars, smallValues = partitionScalars(scalars, C, config.ScalarsMont, config.NbTasks) - - // if we have more than 10% of small values, we split the processing of the first chunk in 2 - // we may want to do that in msmInnerG2Jac , but that would incur a cost of looping through all scalars one more time - splitFirstChunk := (float64(smallValues) / float64(len(scalars))) >= 0.1 - - // we have nbSplits intermediate results that we must sum together. - _p := make([]G2Jac, nbSplits-1) - chDone := make(chan int, nbSplits-1) - for i := 0; i < nbSplits-1; i++ { - start := i * nbPoints - end := start + nbPoints - go func(start, end, i int) { - msmInnerG2Jac(&_p[i], int(C), points[start:end], scalars[start:end], splitFirstChunk) - chDone <- i - }(start, end, i) - } - - msmInnerG2Jac(p, int(C), points[(nbSplits-1)*nbPoints:], scalars[(nbSplits-1)*nbPoints:], splitFirstChunk) - for i := 0; i < nbSplits-1; i++ { - done := <-chDone - p.AddAssign(&_p[done]) - } - close(chDone) - return p, nil -} - -func msmInnerG2Jac(p *G2Jac, c int, points []G2Affine, scalars []fr.Element, splitFirstChunk bool) { - - switch c { - - case 4: - p.msmC4(points, scalars, splitFirstChunk) - - case 5: - p.msmC5(points, scalars, splitFirstChunk) - - case 6: - p.msmC6(points, scalars, splitFirstChunk) - - case 7: - p.msmC7(points, scalars, splitFirstChunk) - - case 8: - p.msmC8(points, scalars, splitFirstChunk) - - case 9: - p.msmC9(points, scalars, splitFirstChunk) - - case 10: - p.msmC10(points, scalars, splitFirstChunk) - - case 11: - p.msmC11(points, scalars, splitFirstChunk) - - case 12: - p.msmC12(points, scalars, splitFirstChunk) - - case 13: - p.msmC13(points, scalars, splitFirstChunk) - - case 14: - p.msmC14(points, scalars, splitFirstChunk) - - case 15: - p.msmC15(points, scalars, splitFirstChunk) - - case 16: - p.msmC16(points, scalars, splitFirstChunk) - - case 20: - p.msmC20(points, scalars, splitFirstChunk) - - case 21: - p.msmC21(points, scalars, splitFirstChunk) - - case 22: - p.msmC22(points, scalars, splitFirstChunk) - - default: - panic("not implemented") - } -} - -// msmReduceChunkG2Affine reduces the weighted sum of the buckets into the result of the multiExp -func msmReduceChunkG2Affine(p *G2Jac, c int, chChunks []chan g2JacExtended) *G2Jac { - var _p g2JacExtended - totalj := <-chChunks[len(chChunks)-1] - _p.Set(&totalj) - for j := len(chChunks) - 2; j >= 0; j-- { - for l := 0; l < c; l++ { - _p.double(&_p) - } - totalj := <-chChunks[j] - _p.add(&totalj) - } - - return p.unsafeFromJacExtended(&_p) -} - -func msmProcessChunkG2Affine(chunk uint64, - chRes chan<- g2JacExtended, - buckets []g2JacExtended, - c uint64, - points []G2Affine, - scalars []fr.Element) { - - mask := uint64((1 << c) - 1) // low c bits are 1 - msbWindow := uint64(1 << (c - 1)) - - for i := 0; i < len(buckets); i++ { - buckets[i].setInfinity() - } - - jc := uint64(chunk * c) - s := selector{} - s.index = jc / 64 - s.shift = jc - (s.index * 64) - s.mask = mask << s.shift - s.multiWordSelect = (64%c) != 0 && s.shift > (64-c) && s.index < (fr.Limbs-1) - if s.multiWordSelect { - nbBitsHigh := s.shift - uint64(64-c) - s.maskHigh = (1 << nbBitsHigh) - 1 - s.shiftHigh = (c - nbBitsHigh) - } - - // for each scalars, get the digit corresponding to the chunk we're processing. - for i := 0; i < len(scalars); i++ { - bits := (scalars[i][s.index] & s.mask) >> s.shift - if s.multiWordSelect { - bits += (scalars[i][s.index+1] & s.maskHigh) << s.shiftHigh - } - - if bits == 0 { - continue - } - - // if msbWindow bit is set, we need to substract - if bits&msbWindow == 0 { - // add - buckets[bits-1].addMixed(&points[i]) - } else { - // sub - buckets[bits & ^msbWindow].subMixed(&points[i]) - } - } - - // reduce buckets into total - // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] - - var runningSum, total g2JacExtended - runningSum.setInfinity() - total.setInfinity() - for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { - runningSum.add(&buckets[k]) - } - total.add(&runningSum) - } - - chRes <- total - -} - -func (p *G2Jac) msmC4(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 4 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} - -func (p *G2Jac) msmC5(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 5 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} - -func (p *G2Jac) msmC6(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 6 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} - -func (p *G2Jac) msmC7(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 7 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} - -func (p *G2Jac) msmC8(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 8 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} - -func (p *G2Jac) msmC9(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 9 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} - -func (p *G2Jac) msmC10(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 10 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} - -func (p *G2Jac) msmC11(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 11 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() + case 2: + return processChunkG2Jacobian[bucketg2JacExtendedC2] + case 3: + return processChunkG2Jacobian[bucketg2JacExtendedC3] + case 4: + return processChunkG2Jacobian[bucketg2JacExtendedC4] + case 5: + return processChunkG2Jacobian[bucketg2JacExtendedC5] + case 6: + return processChunkG2Jacobian[bucketg2JacExtendedC6] + case 7: + return processChunkG2Jacobian[bucketg2JacExtendedC7] + case 8: + return processChunkG2Jacobian[bucketg2JacExtendedC8] + case 9: + return processChunkG2Jacobian[bucketg2JacExtendedC9] + case 10: + const batchSize = 80 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC10] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC10, bucketG2AffineC10, bitSetC10, pG2AffineC10, ppG2AffineC10, qG2AffineC10, cG2AffineC10] + case 11: + const batchSize = 150 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC11] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC11, bucketG2AffineC11, bitSetC11, pG2AffineC11, ppG2AffineC11, qG2AffineC11, cG2AffineC11] + case 12: + const batchSize = 200 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC12] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC12, bucketG2AffineC12, bitSetC12, pG2AffineC12, ppG2AffineC12, qG2AffineC12, cG2AffineC12] + case 13: + const batchSize = 350 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC13] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC13, bucketG2AffineC13, bitSetC13, pG2AffineC13, ppG2AffineC13, qG2AffineC13, cG2AffineC13] + case 14: + const batchSize = 400 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC14] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC14, bucketG2AffineC14, bitSetC14, pG2AffineC14, ppG2AffineC14, qG2AffineC14, cG2AffineC14] + case 15: + const batchSize = 500 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC15] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC15, bucketG2AffineC15, bitSetC15, pG2AffineC15, ppG2AffineC15, qG2AffineC15, cG2AffineC15] + case 16: + const batchSize = 640 + // here we could check some chunk statistic (deviation, ...) to determine if calling + // the batch affine version is worth it. + if stat.nbBucketFilled < batchSize { + // clear indicator that batch affine method is not appropriate here. + return processChunkG2Jacobian[bucketg2JacExtendedC16] + } + return processChunkG2BatchAffine[bucketg2JacExtendedC16, bucketG2AffineC16, bitSetC16, pG2AffineC16, ppG2AffineC16, qG2AffineC16, cG2AffineC16] + default: + // panic("will not happen c != previous values is not generated by templates") + return processChunkG2Jacobian[bucketg2JacExtendedC16] } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) } -func (p *G2Jac) msmC12(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 12 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() +// msmReduceChunkG2Affine reduces the weighted sum of the buckets into the result of the multiExp +func msmReduceChunkG2Affine(p *G2Jac, c int, chChunks []chan g2JacExtended) *G2Jac { + var _p g2JacExtended + totalj := <-chChunks[len(chChunks)-1] + _p.Set(&totalj) + for j := len(chChunks) - 2; j >= 0; j-- { + for l := 0; l < c; l++ { + _p.double(&_p) + } + totalj := <-chChunks[j] + _p.add(&totalj) } - return msmReduceChunkG2Affine(p, c, chChunks[:]) + return p.unsafeFromJacExtended(&_p) } -func (p *G2Jac) msmC13(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 13 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } +// selector stores the index, mask and shifts needed to select bits from a scalar +// it is used during the multiExp algorithm or the batch scalar multiplication +type selector struct { + index uint64 // index in the multi-word scalar to select bits from + mask uint64 // mask (c-bit wide) + shift uint64 // shift needed to get our bits on low positions - return msmReduceChunkG2Affine(p, c, chChunks[:]) + multiWordSelect bool // set to true if we need to select bits from 2 words (case where c doesn't divide 64) + maskHigh uint64 // same than mask, for index+1 + shiftHigh uint64 // same than shift, for index+1 } -func (p *G2Jac) msmC14(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 14 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) +// return number of chunks for a given window size c +// the last chunk may be bigger to accommodate a potential carry from the NAF decomposition +func computeNbChunks(c uint64) uint64 { + return (fr.Bits + c - 1) / c } -func (p *G2Jac) msmC15(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 15 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } - - return msmReduceChunkG2Affine(p, c, chChunks[:]) +// return the last window size for a scalar; +// this last window should accommodate a carry (from the NAF decomposition) +// it can be == c if we have 1 available bit +// it can be > c if we have 0 available bit +// it can be < c if we have 2+ available bits +func lastC(c uint64) uint64 { + nbAvailableBits := (computeNbChunks(c) * c) - fr.Bits + return c + 1 - nbAvailableBits } -func (p *G2Jac) msmC16(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 16 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } - - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } - - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } - - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } +type chunkStat struct { + // relative weight of work compared to other chunks. 100.0 -> nominal weight. + weight float32 - return msmReduceChunkG2Affine(p, c, chChunks[:]) + // percentage of bucket filled in the window; + ppBucketFilled float32 + nbBucketFilled int } -func (p *G2Jac) msmC20(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 20 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) - - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance - - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) +// partitionScalars compute, for each scalars over c-bit wide windows, nbChunk digits +// if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract +// 2^{c} to the current digit, making it negative. +// negative digits can be processed in a later step as adding -G into the bucket instead of G +// (computing -G is cheap, and this saves us half of the buckets in the MultiExp or BatchScalarMultiplication) +func partitionScalars(scalars []fr.Element, c uint64, nbTasks int) ([]uint16, []chunkStat) { + // no benefit here to have more tasks than CPUs + if nbTasks > runtime.NumCPU() { + nbTasks = runtime.NumCPU() } - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) + // number of c-bit radixes in a scalar + nbChunks := computeNbChunks(c) - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } + digits := make([]uint16, len(scalars)*int(nbChunks)) - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } + mask := uint64((1 << c) - 1) // low c bits are 1 + max := int(1<<(c-1)) - 1 // max value (inclusive) we want for our digits + cDivides64 := (64 % c) == 0 // if c doesn't divide 64, we may need to select over multiple words - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() + // compute offset and word selector / shift to select the right bits of our windows + selectors := make([]selector, nbChunks) + for chunk := uint64(0); chunk < nbChunks; chunk++ { + jc := uint64(chunk * c) + d := selector{} + d.index = jc / 64 + d.shift = jc - (d.index * 64) + d.mask = mask << d.shift + d.multiWordSelect = !cDivides64 && d.shift > (64-c) && d.index < (fr.Limbs-1) + if d.multiWordSelect { + nbBitsHigh := d.shift - uint64(64-c) + d.maskHigh = (1 << nbBitsHigh) - 1 + d.shiftHigh = (c - nbBitsHigh) + } + selectors[chunk] = d } - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} + parallel.Execute(len(scalars), func(start, end int) { + for i := start; i < end; i++ { + if scalars[i].IsZero() { + // everything is 0, no need to process this scalar + continue + } + scalar := scalars[i].Bits() -func (p *G2Jac) msmC21(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 21 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) + var carry int - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance + // for each chunk in the scalar, compute the current digit, and an eventual carry + for chunk := uint64(0); chunk < nbChunks-1; chunk++ { + s := selectors[chunk] - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) - } + // init with carry if any + digit := carry + carry = 0 - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) + // digit = value of the c-bit window + digit += int((scalar[s.index] & s.mask) >> s.shift) - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } + if s.multiWordSelect { + // we are selecting bits over 2 words + digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh + } - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) - } + // if the digit is larger than 2^{c-1}, then, we borrow 2^c from the next window and subtract + // 2^{c} to the current digit, making it negative. + if digit > max { + digit -= (1 << c) + carry = 1 + } - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() - } + // if digit is zero, no impact on result + if digit == 0 { + continue + } - return msmReduceChunkG2Affine(p, c, chChunks[:]) -} + var bits uint16 + if digit > 0 { + bits = uint16(digit) << 1 + } else { + bits = (uint16(-digit-1) << 1) + 1 + } + digits[int(chunk)*len(scalars)+i] = bits + } -func (p *G2Jac) msmC22(points []G2Affine, scalars []fr.Element, splitFirstChunk bool) *G2Jac { - const ( - c = 22 // scalars partitioned into c-bit radixes - nbChunks = (fr.Limbs * 64 / c) // number of c-bit radixes in a scalar - ) + // for the last chunk, we don't want to borrow from a next window + // (but may have a larger max value) + chunk := nbChunks - 1 + s := selectors[chunk] + // init with carry if any + digit := carry + // digit = value of the c-bit window + digit += int((scalar[s.index] & s.mask) >> s.shift) + if s.multiWordSelect { + // we are selecting bits over 2 words + digit += int(scalar[s.index+1]&s.maskHigh) << s.shiftHigh + } + digits[int(chunk)*len(scalars)+i] = uint16(digit) << 1 + } - // for each chunk, spawn one go routine that'll loop through all the scalars in the - // corresponding bit-window - // note that buckets is an array allocated on the stack (for most sizes of c) and this is - // critical for performance + }, nbTasks) - // each go routine sends its result in chChunks[i] channel - var chChunks [nbChunks + 1]chan g2JacExtended - for i := 0; i < len(chChunks); i++ { - chChunks[i] = make(chan g2JacExtended, 1) + // aggregate chunk stats + chunkStats := make([]chunkStat, nbChunks) + if c <= 9 { + // no need to compute stats for small window sizes + return digits, chunkStats } + parallel.Execute(len(chunkStats), func(start, end int) { + // for each chunk compute the statistics + for chunkID := start; chunkID < end; chunkID++ { + // indicates if a bucket is hit. + var b bitSetC16 - // c doesn't divide 256, last window is smaller we can allocate less buckets - const lastC = (fr.Limbs * 64) - (c * (fr.Limbs * 64 / c)) - go func(j uint64, points []G2Affine, scalars []fr.Element) { - var buckets [1 << (lastC - 1)]g2JacExtended - msmProcessChunkG2Affine(j, chChunks[j], buckets[:], c, points, scalars) - }(uint64(nbChunks), points, scalars) + // digits for the chunk + chunkDigits := digits[chunkID*len(scalars) : (chunkID+1)*len(scalars)] - processChunk := func(j int, points []G2Affine, scalars []fr.Element, chChunk chan g2JacExtended) { - var buckets [1 << (c - 1)]g2JacExtended - msmProcessChunkG2Affine(uint64(j), chChunk, buckets[:], c, points, scalars) - } + totalOps := 0 + nz := 0 // non zero buckets count + for _, digit := range chunkDigits { + if digit == 0 { + continue + } + totalOps++ + bucketID := digit >> 1 + if digit&1 == 0 { + bucketID -= 1 + } + if !b[bucketID] { + nz++ + b[bucketID] = true + } + } + chunkStats[chunkID].weight = float32(totalOps) // count number of ops for now, we will compute the weight after + chunkStats[chunkID].ppBucketFilled = (float32(nz) * 100.0) / float32(int(1<<(c-1))) + chunkStats[chunkID].nbBucketFilled = nz + } + }, nbTasks) - for j := int(nbChunks - 1); j > 0; j-- { - go processChunk(j, points, scalars, chChunks[j]) + totalOps := float32(0.0) + for _, stat := range chunkStats { + totalOps += stat.weight } - if !splitFirstChunk { - go processChunk(0, points, scalars, chChunks[0]) - } else { - chSplit := make(chan g2JacExtended, 2) - split := len(points) / 2 - go processChunk(0, points[:split], scalars[:split], chSplit) - go processChunk(0, points[split:], scalars[split:], chSplit) - go func() { - s1 := <-chSplit - s2 := <-chSplit - close(chSplit) - s1.add(&s2) - chChunks[0] <- s1 - }() + target := totalOps / float32(nbChunks) + if target != 0.0 { + // if target == 0, it means all the scalars are 0 everywhere, there is no work to be done. + for i := 0; i < len(chunkStats); i++ { + chunkStats[i].weight = (chunkStats[i].weight * 100.0) / target + } } - return msmReduceChunkG2Affine(p, c, chChunks[:]) + return digits, chunkStats } diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_affine.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_affine.go new file mode 100644 index 00000000000..0958526ea74 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_affine.go @@ -0,0 +1,712 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bn254 + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" +) + +type batchOpG1Affine struct { + bucketID uint16 + point G1Affine +} + +// processChunkG1BatchAffine process a chunk of the scalars during the msm +// using affine coordinates for the buckets. To amortize the cost of the inverse in the affine addition +// we use a batch affine addition. +// +// this is derived from a PR by 0x0ece : https://github.com/ConsenSys/gnark-crypto/pull/249 +// See Section 5.3: ia.cr/2022/1396 +func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP pG1Affine, TPP ppG1Affine, TQ qOpsG1Affine, TC cG1Affine]( + chunk uint64, + chRes chan<- g1JacExtended, + c uint64, + points []G1Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + // the batch affine addition needs independent points; in other words, for a window of batchSize + // we want to hit independent bucketIDs when processing the digit. if there is a conflict (we're trying + // to add 2 different points to the same bucket), then we push the conflicted point to a queue. + // each time the batch is full, we execute it, and tentatively put the points (if not conflict) + // from the top of the queue into the next batch. + // if the queue is full, we "flush it"; we sequentially add the points to the buckets in + // g1JacExtended coordinates. + // The reasoning behind this is the following; batchSize is chosen such as, for a uniformly random + // input, the number of conflicts is going to be low, and the element added to the queue should be immediately + // processed in the next batch. If it's not the case, then our inputs are not random; and we fallback to + // non-batch-affine version. + + // note that we have 2 sets of buckets + // 1 in G1Affine used with the batch affine additions + // 1 in g1JacExtended used in case the queue of conflicting points + var buckets B + var bucketsJE BJE + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + bucketsJE[i].setInfinity() + } + + // setup for the batch affine; + var ( + bucketIds BS // bitSet to signify presence of a bucket in current batch + cptAdd int // count the number of bucket + point added to current batch + R TPP // bucket references + P TP // points to be added to R (buckets); it is beneficial to store them on the stack (ie copy) + queue TQ // queue of points that conflict the current batch + qID int // current position in queue + ) + + batchSize := len(P) + + isFull := func() bool { return cptAdd == batchSize } + + executeAndReset := func() { + batchAddG1Affine[TP, TPP, TC](&R, &P, cptAdd) + var tmp BS + bucketIds = tmp + cptAdd = 0 + } + + addFromQueue := func(op batchOpG1Affine) { + // @precondition: must ensures bucket is not "used" in current batch + // note that there is a bit of duplicate logic between add and addFromQueue + // the reason is that as of Go 1.19.3, if we pass a pointer to the queue item (see add signature) + // the compiler will put the queue on the heap. + BK := &buckets[op.bucketID] + + // handle special cases with inf or -P / P + if BK.IsInfinity() { + BK.Set(&op.point) + return + } + if BK.X.Equal(&op.point.X) { + if BK.Y.Equal(&op.point.Y) { + // P + P: doubling, which should be quite rare -- + // we use the other set of buckets + bucketsJE[op.bucketID].addMixed(&op.point) + return + } + BK.setInfinity() + return + } + + bucketIds[op.bucketID] = true + R[cptAdd] = BK + P[cptAdd] = op.point + cptAdd++ + } + + add := func(bucketID uint16, PP *G1Affine, isAdd bool) { + // @precondition: ensures bucket is not "used" in current batch + BK := &buckets[bucketID] + // handle special cases with inf or -P / P + if BK.IsInfinity() { + if isAdd { + BK.Set(PP) + } else { + BK.Neg(PP) + } + return + } + if BK.X.Equal(&PP.X) { + if BK.Y.Equal(&PP.Y) { + // P + P: doubling, which should be quite rare -- + if isAdd { + bucketsJE[bucketID].addMixed(PP) + } else { + BK.setInfinity() + } + return + } + if isAdd { + BK.setInfinity() + } else { + bucketsJE[bucketID].subMixed(PP) + } + return + } + + bucketIds[bucketID] = true + R[cptAdd] = BK + if isAdd { + P[cptAdd].Set(PP) + } else { + P[cptAdd].Neg(PP) + } + cptAdd++ + } + + flushQueue := func() { + for i := 0; i < qID; i++ { + bucketsJE[queue[i].bucketID].addMixed(&queue[i].point) + } + qID = 0 + } + + processTopQueue := func() { + for i := qID - 1; i >= 0; i-- { + if bucketIds[queue[i].bucketID] { + return + } + addFromQueue(queue[i]) + // len(queue) < batchSize so no need to check for full batch. + qID-- + } + } + + for i, digit := range digits { + + if digit == 0 || points[i].IsInfinity() { + continue + } + + bucketID := uint16((digit >> 1)) + isAdd := digit&1 == 0 + if isAdd { + // add + bucketID -= 1 + } + + if bucketIds[bucketID] { + // put it in queue + queue[qID].bucketID = bucketID + if isAdd { + queue[qID].point.Set(&points[i]) + } else { + queue[qID].point.Neg(&points[i]) + } + qID++ + + // queue is full, flush it. + if qID == len(queue)-1 { + flushQueue() + } + continue + } + + // we add the point to the batch. + add(bucketID, &points[i], isAdd) + if isFull() { + executeAndReset() + processTopQueue() + } + } + + // flush items in batch. + executeAndReset() + + // empty the queue + flushQueue() + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + var runningSum, total g1JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + runningSum.addMixed(&buckets[k]) + if !bucketsJE[k].IsZero() { + runningSum.add(&bucketsJE[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total + +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketG1AffineC10 [512]G1Affine +type bucketG1AffineC11 [1024]G1Affine +type bucketG1AffineC12 [2048]G1Affine +type bucketG1AffineC13 [4096]G1Affine +type bucketG1AffineC14 [8192]G1Affine +type bucketG1AffineC15 [16384]G1Affine +type bucketG1AffineC16 [32768]G1Affine + +// buckets: array of G1Affine points of size 1 << (c-1) +type ibG1Affine interface { + bucketG1AffineC10 | + bucketG1AffineC11 | + bucketG1AffineC12 | + bucketG1AffineC13 | + bucketG1AffineC14 | + bucketG1AffineC15 | + bucketG1AffineC16 +} + +// array of coordinates fp.Element +type cG1Affine interface { + cG1AffineC10 | + cG1AffineC11 | + cG1AffineC12 | + cG1AffineC13 | + cG1AffineC14 | + cG1AffineC15 | + cG1AffineC16 +} + +// buckets: array of G1Affine points (for the batch addition) +type pG1Affine interface { + pG1AffineC10 | + pG1AffineC11 | + pG1AffineC12 | + pG1AffineC13 | + pG1AffineC14 | + pG1AffineC15 | + pG1AffineC16 +} + +// buckets: array of *G1Affine points (for the batch addition) +type ppG1Affine interface { + ppG1AffineC10 | + ppG1AffineC11 | + ppG1AffineC12 | + ppG1AffineC13 | + ppG1AffineC14 | + ppG1AffineC15 | + ppG1AffineC16 +} + +// buckets: array of G1Affine queue operations (for the batch addition) +type qOpsG1Affine interface { + qG1AffineC10 | + qG1AffineC11 | + qG1AffineC12 | + qG1AffineC13 | + qG1AffineC14 | + qG1AffineC15 | + qG1AffineC16 +} + +// batch size 80 when c = 10 +type cG1AffineC10 [80]fp.Element +type pG1AffineC10 [80]G1Affine +type ppG1AffineC10 [80]*G1Affine +type qG1AffineC10 [80]batchOpG1Affine + +// batch size 150 when c = 11 +type cG1AffineC11 [150]fp.Element +type pG1AffineC11 [150]G1Affine +type ppG1AffineC11 [150]*G1Affine +type qG1AffineC11 [150]batchOpG1Affine + +// batch size 200 when c = 12 +type cG1AffineC12 [200]fp.Element +type pG1AffineC12 [200]G1Affine +type ppG1AffineC12 [200]*G1Affine +type qG1AffineC12 [200]batchOpG1Affine + +// batch size 350 when c = 13 +type cG1AffineC13 [350]fp.Element +type pG1AffineC13 [350]G1Affine +type ppG1AffineC13 [350]*G1Affine +type qG1AffineC13 [350]batchOpG1Affine + +// batch size 400 when c = 14 +type cG1AffineC14 [400]fp.Element +type pG1AffineC14 [400]G1Affine +type ppG1AffineC14 [400]*G1Affine +type qG1AffineC14 [400]batchOpG1Affine + +// batch size 500 when c = 15 +type cG1AffineC15 [500]fp.Element +type pG1AffineC15 [500]G1Affine +type ppG1AffineC15 [500]*G1Affine +type qG1AffineC15 [500]batchOpG1Affine + +// batch size 640 when c = 16 +type cG1AffineC16 [640]fp.Element +type pG1AffineC16 [640]G1Affine +type ppG1AffineC16 [640]*G1Affine +type qG1AffineC16 [640]batchOpG1Affine + +type batchOpG2Affine struct { + bucketID uint16 + point G2Affine +} + +// processChunkG2BatchAffine process a chunk of the scalars during the msm +// using affine coordinates for the buckets. To amortize the cost of the inverse in the affine addition +// we use a batch affine addition. +// +// this is derived from a PR by 0x0ece : https://github.com/ConsenSys/gnark-crypto/pull/249 +// See Section 5.3: ia.cr/2022/1396 +func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP pG2Affine, TPP ppG2Affine, TQ qOpsG2Affine, TC cG2Affine]( + chunk uint64, + chRes chan<- g2JacExtended, + c uint64, + points []G2Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + // the batch affine addition needs independent points; in other words, for a window of batchSize + // we want to hit independent bucketIDs when processing the digit. if there is a conflict (we're trying + // to add 2 different points to the same bucket), then we push the conflicted point to a queue. + // each time the batch is full, we execute it, and tentatively put the points (if not conflict) + // from the top of the queue into the next batch. + // if the queue is full, we "flush it"; we sequentially add the points to the buckets in + // g2JacExtended coordinates. + // The reasoning behind this is the following; batchSize is chosen such as, for a uniformly random + // input, the number of conflicts is going to be low, and the element added to the queue should be immediately + // processed in the next batch. If it's not the case, then our inputs are not random; and we fallback to + // non-batch-affine version. + + // note that we have 2 sets of buckets + // 1 in G2Affine used with the batch affine additions + // 1 in g2JacExtended used in case the queue of conflicting points + var buckets B + var bucketsJE BJE + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + bucketsJE[i].setInfinity() + } + + // setup for the batch affine; + var ( + bucketIds BS // bitSet to signify presence of a bucket in current batch + cptAdd int // count the number of bucket + point added to current batch + R TPP // bucket references + P TP // points to be added to R (buckets); it is beneficial to store them on the stack (ie copy) + queue TQ // queue of points that conflict the current batch + qID int // current position in queue + ) + + batchSize := len(P) + + isFull := func() bool { return cptAdd == batchSize } + + executeAndReset := func() { + batchAddG2Affine[TP, TPP, TC](&R, &P, cptAdd) + var tmp BS + bucketIds = tmp + cptAdd = 0 + } + + addFromQueue := func(op batchOpG2Affine) { + // @precondition: must ensures bucket is not "used" in current batch + // note that there is a bit of duplicate logic between add and addFromQueue + // the reason is that as of Go 1.19.3, if we pass a pointer to the queue item (see add signature) + // the compiler will put the queue on the heap. + BK := &buckets[op.bucketID] + + // handle special cases with inf or -P / P + if BK.IsInfinity() { + BK.Set(&op.point) + return + } + if BK.X.Equal(&op.point.X) { + if BK.Y.Equal(&op.point.Y) { + // P + P: doubling, which should be quite rare -- + // we use the other set of buckets + bucketsJE[op.bucketID].addMixed(&op.point) + return + } + BK.setInfinity() + return + } + + bucketIds[op.bucketID] = true + R[cptAdd] = BK + P[cptAdd] = op.point + cptAdd++ + } + + add := func(bucketID uint16, PP *G2Affine, isAdd bool) { + // @precondition: ensures bucket is not "used" in current batch + BK := &buckets[bucketID] + // handle special cases with inf or -P / P + if BK.IsInfinity() { + if isAdd { + BK.Set(PP) + } else { + BK.Neg(PP) + } + return + } + if BK.X.Equal(&PP.X) { + if BK.Y.Equal(&PP.Y) { + // P + P: doubling, which should be quite rare -- + if isAdd { + bucketsJE[bucketID].addMixed(PP) + } else { + BK.setInfinity() + } + return + } + if isAdd { + BK.setInfinity() + } else { + bucketsJE[bucketID].subMixed(PP) + } + return + } + + bucketIds[bucketID] = true + R[cptAdd] = BK + if isAdd { + P[cptAdd].Set(PP) + } else { + P[cptAdd].Neg(PP) + } + cptAdd++ + } + + flushQueue := func() { + for i := 0; i < qID; i++ { + bucketsJE[queue[i].bucketID].addMixed(&queue[i].point) + } + qID = 0 + } + + processTopQueue := func() { + for i := qID - 1; i >= 0; i-- { + if bucketIds[queue[i].bucketID] { + return + } + addFromQueue(queue[i]) + // len(queue) < batchSize so no need to check for full batch. + qID-- + } + } + + for i, digit := range digits { + + if digit == 0 || points[i].IsInfinity() { + continue + } + + bucketID := uint16((digit >> 1)) + isAdd := digit&1 == 0 + if isAdd { + // add + bucketID -= 1 + } + + if bucketIds[bucketID] { + // put it in queue + queue[qID].bucketID = bucketID + if isAdd { + queue[qID].point.Set(&points[i]) + } else { + queue[qID].point.Neg(&points[i]) + } + qID++ + + // queue is full, flush it. + if qID == len(queue)-1 { + flushQueue() + } + continue + } + + // we add the point to the batch. + add(bucketID, &points[i], isAdd) + if isFull() { + executeAndReset() + processTopQueue() + } + } + + // flush items in batch. + executeAndReset() + + // empty the queue + flushQueue() + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + var runningSum, total g2JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + runningSum.addMixed(&buckets[k]) + if !bucketsJE[k].IsZero() { + runningSum.add(&bucketsJE[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total + +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketG2AffineC10 [512]G2Affine +type bucketG2AffineC11 [1024]G2Affine +type bucketG2AffineC12 [2048]G2Affine +type bucketG2AffineC13 [4096]G2Affine +type bucketG2AffineC14 [8192]G2Affine +type bucketG2AffineC15 [16384]G2Affine +type bucketG2AffineC16 [32768]G2Affine + +// buckets: array of G2Affine points of size 1 << (c-1) +type ibG2Affine interface { + bucketG2AffineC10 | + bucketG2AffineC11 | + bucketG2AffineC12 | + bucketG2AffineC13 | + bucketG2AffineC14 | + bucketG2AffineC15 | + bucketG2AffineC16 +} + +// array of coordinates fptower.E2 +type cG2Affine interface { + cG2AffineC10 | + cG2AffineC11 | + cG2AffineC12 | + cG2AffineC13 | + cG2AffineC14 | + cG2AffineC15 | + cG2AffineC16 +} + +// buckets: array of G2Affine points (for the batch addition) +type pG2Affine interface { + pG2AffineC10 | + pG2AffineC11 | + pG2AffineC12 | + pG2AffineC13 | + pG2AffineC14 | + pG2AffineC15 | + pG2AffineC16 +} + +// buckets: array of *G2Affine points (for the batch addition) +type ppG2Affine interface { + ppG2AffineC10 | + ppG2AffineC11 | + ppG2AffineC12 | + ppG2AffineC13 | + ppG2AffineC14 | + ppG2AffineC15 | + ppG2AffineC16 +} + +// buckets: array of G2Affine queue operations (for the batch addition) +type qOpsG2Affine interface { + qG2AffineC10 | + qG2AffineC11 | + qG2AffineC12 | + qG2AffineC13 | + qG2AffineC14 | + qG2AffineC15 | + qG2AffineC16 +} + +// batch size 80 when c = 10 +type cG2AffineC10 [80]fptower.E2 +type pG2AffineC10 [80]G2Affine +type ppG2AffineC10 [80]*G2Affine +type qG2AffineC10 [80]batchOpG2Affine + +// batch size 150 when c = 11 +type cG2AffineC11 [150]fptower.E2 +type pG2AffineC11 [150]G2Affine +type ppG2AffineC11 [150]*G2Affine +type qG2AffineC11 [150]batchOpG2Affine + +// batch size 200 when c = 12 +type cG2AffineC12 [200]fptower.E2 +type pG2AffineC12 [200]G2Affine +type ppG2AffineC12 [200]*G2Affine +type qG2AffineC12 [200]batchOpG2Affine + +// batch size 350 when c = 13 +type cG2AffineC13 [350]fptower.E2 +type pG2AffineC13 [350]G2Affine +type ppG2AffineC13 [350]*G2Affine +type qG2AffineC13 [350]batchOpG2Affine + +// batch size 400 when c = 14 +type cG2AffineC14 [400]fptower.E2 +type pG2AffineC14 [400]G2Affine +type ppG2AffineC14 [400]*G2Affine +type qG2AffineC14 [400]batchOpG2Affine + +// batch size 500 when c = 15 +type cG2AffineC15 [500]fptower.E2 +type pG2AffineC15 [500]G2Affine +type ppG2AffineC15 [500]*G2Affine +type qG2AffineC15 [500]batchOpG2Affine + +// batch size 640 when c = 16 +type cG2AffineC16 [640]fptower.E2 +type pG2AffineC16 [640]G2Affine +type ppG2AffineC16 [640]*G2Affine +type qG2AffineC16 [640]batchOpG2Affine + +type bitSetC2 [2]bool +type bitSetC3 [4]bool +type bitSetC4 [8]bool +type bitSetC5 [16]bool +type bitSetC6 [32]bool +type bitSetC7 [64]bool +type bitSetC8 [128]bool +type bitSetC9 [256]bool +type bitSetC10 [512]bool +type bitSetC11 [1024]bool +type bitSetC12 [2048]bool +type bitSetC13 [4096]bool +type bitSetC14 [8192]bool +type bitSetC15 [16384]bool +type bitSetC16 [32768]bool + +type bitSet interface { + bitSetC2 | + bitSetC3 | + bitSetC4 | + bitSetC5 | + bitSetC6 | + bitSetC7 | + bitSetC8 | + bitSetC9 | + bitSetC10 | + bitSetC11 | + bitSetC12 | + bitSetC13 | + bitSetC14 | + bitSetC15 | + bitSetC16 +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_jacobian.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_jacobian.go new file mode 100644 index 00000000000..32f728fc052 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_jacobian.go @@ -0,0 +1,199 @@ +// Copyright 2020 Consensys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package bn254 + +func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, + chRes chan<- g1JacExtended, + c uint64, + points []G1Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + var buckets B + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i, digit := range digits { + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + buckets[(digit>>1)-1].addMixed(&points[i]) + } else { + // sub + buckets[(digit >> 1)].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g1JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketg1JacExtendedC2 [2]g1JacExtended +type bucketg1JacExtendedC3 [4]g1JacExtended +type bucketg1JacExtendedC4 [8]g1JacExtended +type bucketg1JacExtendedC5 [16]g1JacExtended +type bucketg1JacExtendedC6 [32]g1JacExtended +type bucketg1JacExtendedC7 [64]g1JacExtended +type bucketg1JacExtendedC8 [128]g1JacExtended +type bucketg1JacExtendedC9 [256]g1JacExtended +type bucketg1JacExtendedC10 [512]g1JacExtended +type bucketg1JacExtendedC11 [1024]g1JacExtended +type bucketg1JacExtendedC12 [2048]g1JacExtended +type bucketg1JacExtendedC13 [4096]g1JacExtended +type bucketg1JacExtendedC14 [8192]g1JacExtended +type bucketg1JacExtendedC15 [16384]g1JacExtended +type bucketg1JacExtendedC16 [32768]g1JacExtended + +type ibg1JacExtended interface { + bucketg1JacExtendedC2 | + bucketg1JacExtendedC3 | + bucketg1JacExtendedC4 | + bucketg1JacExtendedC5 | + bucketg1JacExtendedC6 | + bucketg1JacExtendedC7 | + bucketg1JacExtendedC8 | + bucketg1JacExtendedC9 | + bucketg1JacExtendedC10 | + bucketg1JacExtendedC11 | + bucketg1JacExtendedC12 | + bucketg1JacExtendedC13 | + bucketg1JacExtendedC14 | + bucketg1JacExtendedC15 | + bucketg1JacExtendedC16 +} + +func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, + chRes chan<- g2JacExtended, + c uint64, + points []G2Affine, + digits []uint16, + sem chan struct{}) { + + if sem != nil { + // if we are limited, wait for a token in the semaphore + <-sem + } + + var buckets B + for i := 0; i < len(buckets); i++ { + buckets[i].setInfinity() + } + + // for each scalars, get the digit corresponding to the chunk we're processing. + for i, digit := range digits { + if digit == 0 { + continue + } + + // if msbWindow bit is set, we need to subtract + if digit&1 == 0 { + // add + buckets[(digit>>1)-1].addMixed(&points[i]) + } else { + // sub + buckets[(digit >> 1)].subMixed(&points[i]) + } + } + + // reduce buckets into total + // total = bucket[0] + 2*bucket[1] + 3*bucket[2] ... + n*bucket[n-1] + + var runningSum, total g2JacExtended + runningSum.setInfinity() + total.setInfinity() + for k := len(buckets) - 1; k >= 0; k-- { + if !buckets[k].IsZero() { + runningSum.add(&buckets[k]) + } + total.add(&runningSum) + } + + if sem != nil { + // release a token to the semaphore + // before sending to chRes + sem <- struct{}{} + } + + chRes <- total +} + +// we declare the buckets as fixed-size array types +// this allow us to allocate the buckets on the stack +type bucketg2JacExtendedC2 [2]g2JacExtended +type bucketg2JacExtendedC3 [4]g2JacExtended +type bucketg2JacExtendedC4 [8]g2JacExtended +type bucketg2JacExtendedC5 [16]g2JacExtended +type bucketg2JacExtendedC6 [32]g2JacExtended +type bucketg2JacExtendedC7 [64]g2JacExtended +type bucketg2JacExtendedC8 [128]g2JacExtended +type bucketg2JacExtendedC9 [256]g2JacExtended +type bucketg2JacExtendedC10 [512]g2JacExtended +type bucketg2JacExtendedC11 [1024]g2JacExtended +type bucketg2JacExtendedC12 [2048]g2JacExtended +type bucketg2JacExtendedC13 [4096]g2JacExtended +type bucketg2JacExtendedC14 [8192]g2JacExtended +type bucketg2JacExtendedC15 [16384]g2JacExtended +type bucketg2JacExtendedC16 [32768]g2JacExtended + +type ibg2JacExtended interface { + bucketg2JacExtendedC2 | + bucketg2JacExtendedC3 | + bucketg2JacExtendedC4 | + bucketg2JacExtendedC5 | + bucketg2JacExtendedC6 | + bucketg2JacExtendedC7 | + bucketg2JacExtendedC8 | + bucketg2JacExtendedC9 | + bucketg2JacExtendedC10 | + bucketg2JacExtendedC11 | + bucketg2JacExtendedC12 | + bucketg2JacExtendedC13 | + bucketg2JacExtendedC14 | + bucketg2JacExtendedC15 | + bucketg2JacExtendedC16 +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/pairing.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/pairing.go index 5d81cfd9444..ec342fe80e2 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/pairing.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/pairing.go @@ -30,6 +30,9 @@ type lineEvaluation struct { } // Pair calculates the reduced pairing for a set of points +// ∏ᵢ e(Pᵢ, Qᵢ). +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. func Pair(P []G1Affine, Q []G2Affine) (GT, error) { f, err := MillerLoop(P, Q) if err != nil { @@ -39,6 +42,9 @@ func Pair(P []G1Affine, Q []G2Affine) (GT, error) { } // PairingCheck calculates the reduced pairing for a set of points and returns True if the result is One +// ∏ᵢ e(Pᵢ, Qᵢ) =? 1 +// +// This function doesn't check that the inputs are in the correct subgroup. See IsInSubGroup. func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) { f, err := Pair(P, Q) if err != nil { @@ -49,7 +55,10 @@ func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) { return f.Equal(&one), nil } -// FinalExponentiation computes the final expo x**(p**6-1)(p**2+1)(p**4 - p**2 +1)/r +// FinalExponentiation computes the exponentiation (∏ᵢ zᵢ)ᵈ +// where d = (p¹²-1)/r = (p¹²-1)/Φ₁₂(p) ⋅ Φ₁₂(p)/r = (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// we use instead d=s ⋅ (p⁶-1)(p²+1)(p⁴ - p² +1)/r +// where s is the cofactor 2x₀(6x₀²+3x₀+1) func FinalExponentiation(z *GT, _z ...*GT) GT { var result GT @@ -59,69 +68,56 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { result.Mul(&result, e) } - // https://eprint.iacr.org/2008/490.pdf - var mt [4]GT // mt[i] is m^(t^i) - - // easy part - mt[0].Set(&result) - var temp GT - temp.Conjugate(&mt[0]) - mt[0].Inverse(&mt[0]) - temp.Mul(&temp, &mt[0]) - mt[0].FrobeniusSquare(&temp). - Mul(&mt[0], &temp) - - // hard part - mt[1].Expt(&mt[0]) - mt[2].Expt(&mt[1]) - mt[3].Expt(&mt[2]) - - var y [7]GT - - y[1].InverseUnitary(&mt[0]) - y[4].Set(&mt[1]) - y[5].InverseUnitary(&mt[2]) - y[6].Set(&mt[3]) - - mt[0].Frobenius(&mt[0]) - mt[1].Frobenius(&mt[1]) - mt[2].Frobenius(&mt[2]) - mt[3].Frobenius(&mt[3]) - - y[0].Set(&mt[0]) - y[3].InverseUnitary(&mt[1]) - y[4].Mul(&y[4], &mt[2]).InverseUnitary(&y[4]) - y[6].Mul(&y[6], &mt[3]).InverseUnitary(&y[6]) - - mt[0].Frobenius(&mt[0]) - mt[2].Frobenius(&mt[2]) - - y[0].Mul(&y[0], &mt[0]) - y[2].Set(&mt[2]) - - mt[0].Frobenius(&mt[0]) - - y[0].Mul(&y[0], &mt[0]) - - // compute addition chain - mt[0].CyclotomicSquare(&y[6]) - mt[0].Mul(&mt[0], &y[4]) - mt[0].Mul(&mt[0], &y[5]) - mt[1].Mul(&y[3], &y[5]) - mt[1].Mul(&mt[1], &mt[0]) - mt[0].Mul(&mt[0], &y[2]) - mt[1].CyclotomicSquare(&mt[1]) - mt[1].Mul(&mt[1], &mt[0]) - mt[1].CyclotomicSquare(&mt[1]) - mt[0].Mul(&mt[1], &y[1]) - mt[1].Mul(&mt[1], &y[0]) - mt[0].CyclotomicSquare(&mt[0]) - result.Mul(&mt[0], &mt[1]) - - return result + var t [5]GT + + // Easy part + // (p⁶-1)(p²+1) + t[0].Conjugate(&result) + result.Inverse(&result) + t[0].Mul(&t[0], &result) + result.FrobeniusSquare(&t[0]).Mul(&result, &t[0]) + + var one GT + one.SetOne() + if result.Equal(&one) { + return result + } + + // Hard part (up to permutation) + // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r + // Duquesne and Ghammam + // https://eprint.iacr.org/2015/192.pdf + // Fuentes et al. (alg. 6) + t[0].Expt(&result). + Conjugate(&t[0]) + t[0].CyclotomicSquare(&t[0]) + t[1].CyclotomicSquare(&t[0]) + t[1].Mul(&t[0], &t[1]) + t[2].Expt(&t[1]) + t[2].Conjugate(&t[2]) + t[3].Conjugate(&t[1]) + t[1].Mul(&t[2], &t[3]) + t[3].CyclotomicSquare(&t[2]) + t[4].Expt(&t[3]) + t[4].Mul(&t[1], &t[4]) + t[3].Mul(&t[0], &t[4]) + t[0].Mul(&t[2], &t[4]) + t[0].Mul(&result, &t[0]) + t[2].Frobenius(&t[3]) + t[0].Mul(&t[2], &t[0]) + t[2].FrobeniusSquare(&t[4]) + t[0].Mul(&t[2], &t[0]) + t[2].Conjugate(&result) + t[2].Mul(&t[2], &t[3]) + t[2].FrobeniusCube(&t[2]) + t[0].Mul(&t[2], &t[0]) + + return t[0] } -// MillerLoop Miller loop +// MillerLoop computes the multi-Miller loop +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = +// ∏ᵢ { fᵢ_{6x₀+2,Qᵢ}(Pᵢ) · ℓᵢ_{[6x₀+2]Qᵢ,π(Qᵢ)}(Pᵢ) · ℓᵢ_{[6x₀+2]Qᵢ+π(Qᵢ),-π²(Qᵢ)}(Pᵢ) } func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { n := len(P) if n == 0 || n != len(Q) { @@ -151,66 +147,159 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { var result GT result.SetOne() + var l2, l1 lineEvaluation + var prodLines [5]E2 + + // Compute ∏ᵢ { fᵢ_{6x₀+2,Q}(P) } + if n >= 1 { + // i = 64, separately to avoid an E12 Square + // (Square(res) = 1² = 1) + // loopCounter[64] = 0 + // k = 0, separately to avoid MulBy034 (res × ℓ) + // (assign line to res) + + // qProj[0] ← 2qProj[0] and l1 the tangent ℓ passing 2qProj[0] + qProj[0].doubleStep(&l1) + // line evaluation at P[0] (assign) + result.C0.B0.MulByElement(&l1.r0, &p[0].Y) + result.C1.B0.MulByElement(&l1.r1, &p[0].X) + result.C1.B1.Set(&l1.r2) + } - var l lineEvaluation + if n >= 2 { + // k = 1, separately to avoid MulBy034 (res × ℓ) + // (res is also a line at this point, so we use Mul034By034 ℓ × ℓ) + + // qProj[1] ← 2qProj[1] and l1 the tangent ℓ passing 2qProj[1] + qProj[1].doubleStep(&l1) + // line evaluation at P[1] + l1.r0.MulByElement(&l1.r0, &p[1].Y) + l1.r1.MulByElement(&l1.r1, &p[1].X) + // ℓ × res + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &result.C0.B0, &result.C1.B0, &result.C1.B1) + result.C0.B0 = prodLines[0] + result.C0.B1 = prodLines[1] + result.C0.B2 = prodLines[2] + result.C1.B0 = prodLines[3] + result.C1.B1 = prodLines[4] + } + + // k >= 2 + for k := 2; k < n; k++ { + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] + qProj[k].doubleStep(&l1) + // line evaluation at P[k] + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + // ℓ × res + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) + } + + // i = 63, separately to avoid a doubleStep (loopCounter[63]=-1) + // (at this point qProj = 2Q, so 2qProj-Q=3Q is equivalent to qProj+Q=3Q + // this means doubleStep followed by an addMixedStep is equivalent to an + // addMixedStep here) - for i := len(loopCounter) - 2; i >= 0; i-- { + result.Square(&result) + for k := 0; k < n; k++ { + // l2 the line passing qProj[k] and -Q + // (avoids a point addition: qProj[k]-Q) + qProj[k].lineCompute(&l2, &qNeg[k]) + // line evaluation at P[k] + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) + // qProj[k] ← qProj[k]+Q[k] and + // l1 the line ℓ passing qProj[k] and Q[k] + qProj[k].addMixedStep(&l1, &q[k]) + // line evaluation at P[k] + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + // ℓ × ℓ + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res + result.MulBy01234(&prodLines) + } + + // i <= 62 + for i := len(loopCounter) - 4; i >= 0; i-- { + // mutualize the square among n Miller loops + // (∏ᵢfᵢ)² result.Square(&result) for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) - // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + // qProj[k] ← 2qProj[k] and l1 the tangent ℓ passing 2qProj[k] + qProj[k].doubleStep(&l1) + // line evaluation at P[k] + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) if loopCounter[i] == 1 { - qProj[k].AddMixedStep(&l, &q[k]) - // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + // qProj[k] ← qProj[k]+Q[k] and + // l2 the line ℓ passing qProj[k] and Q[k] + qProj[k].addMixedStep(&l2, &q[k]) + // line evaluation at P[k] + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) + // ℓ × ℓ + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res + result.MulBy01234(&prodLines) } else if loopCounter[i] == -1 { - qProj[k].AddMixedStep(&l, &qNeg[k]) - // line evaluation - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + // qProj[k] ← qProj[k]-Q[k] and + // l2 the line ℓ passing qProj[k] and -Q[k] + qProj[k].addMixedStep(&l2, &qNeg[k]) + // line evaluation at P[k] + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) + // ℓ × ℓ + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res + result.MulBy01234(&prodLines) + } else { + // ℓ × res + result.MulBy034(&l1.r0, &l1.r1, &l1.r2) } } } + // Compute ∏ᵢ { ℓᵢ_{[6x₀+2]Q,π(Q)}(P) · ℓᵢ_{[6x₀+2]Q+π(Q),-π²(Q)}(P) } var Q1, Q2 G2Affine - var l0 lineEvaluation - var tmp GT - // cf https://eprint.iacr.org/2010/354.pdf for instance for optimal Ate Pairing for k := 0; k < n; k++ { - //Q1 = Frob(Q) + //Q1 = π(Q) Q1.X.Conjugate(&q[k].X).MulByNonResidue1Power2(&Q1.X) Q1.Y.Conjugate(&q[k].Y).MulByNonResidue1Power3(&Q1.Y) - // Q2 = -Frob2(Q) + // Q2 = -π²(Q) Q2.X.MulByNonResidue2Power2(&q[k].X) Q2.Y.MulByNonResidue2Power3(&q[k].Y).Neg(&Q2.Y) - qProj[k].AddMixedStep(&l0, &Q1) - l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1.MulByElement(&l0.r1, &p[k].X) - - qProj[k].AddMixedStep(&l, &Q2) - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - tmp.Mul034by034(&l.r0, &l.r1, &l.r2, &l0.r0, &l0.r1, &l0.r2) - result.Mul(&result, &tmp) + // qProj[k] ← qProj[k]+π(Q) and + // l1 the line passing qProj[k] and π(Q) + qProj[k].addMixedStep(&l2, &Q1) + // line evaluation at P[k] + l2.r0.MulByElement(&l2.r0, &p[k].Y) + l2.r1.MulByElement(&l2.r1, &p[k].X) + + // l2 the line passing qProj[k] and -π²(Q) + // (avoids a point addition: qProj[k]-π²(Q)) + qProj[k].lineCompute(&l1, &Q2) + // line evaluation at P[k] + l1.r0.MulByElement(&l1.r0, &p[k].Y) + l1.r1.MulByElement(&l1.r1, &p[k].X) + + // ℓ × ℓ + prodLines = fptower.Mul034By034(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + // (ℓ × ℓ) × res + result.MulBy01234(&prodLines) } return result, nil } -// DoubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop +// doubleStep doubles a point in Homogenous projective coordinates, and evaluates the line in Miller loop // https://eprint.iacr.org/2013/722.pdf (Section 4.3) -func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) { +func (p *g2Proj) doubleStep(evaluations *lineEvaluation) { // get some Element from our pool var t1, A, B, C, D, E, EE, F, G, H, I, J, K fptower.E2 @@ -220,7 +309,7 @@ func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) { C.Square(&p.z) D.Double(&C). Add(&D, &C) - E.Mul(&D, &bTwistCurveCoeff) + E.MulBybTwistCurveCoeff(&D) F.Double(&E). Add(&F, &E) G.Add(&B, &F) @@ -249,9 +338,9 @@ func (p *g2Proj) DoubleStep(evaluations *lineEvaluation) { evaluations.r2.Set(&I) } -// AddMixedStep point addition in Mixed Homogenous projective and Affine coordinates +// addMixedStep point addition in Mixed Homogenous projective and Affine coordinates // https://eprint.iacr.org/2013/722.pdf (Section 4.3) -func (p *g2Proj) AddMixedStep(evaluations *lineEvaluation, a *G2Affine) { +func (p *g2Proj) addMixedStep(evaluations *lineEvaluation, a *G2Affine) { // get some Element from our pool var Y2Z1, X2Z1, O, L, C, D, E, F, G, H, t0, t1, t2, J fptower.E2 @@ -285,3 +374,23 @@ func (p *g2Proj) AddMixedStep(evaluations *lineEvaluation, a *G2Affine) { evaluations.r1.Neg(&O) evaluations.r2.Set(&J) } + +// lineCompute computes the line through p in Homogenous projective coordinates +// and a in affine coordinates. It does not compute the resulting point p+a. +func (p *g2Proj) lineCompute(evaluations *lineEvaluation, a *G2Affine) { + + // get some Element from our pool + var Y2Z1, X2Z1, O, L, t2, J fptower.E2 + Y2Z1.Mul(&a.Y, &p.z) + O.Sub(&p.y, &Y2Z1) + X2Z1.Mul(&a.X, &p.z) + L.Sub(&p.x, &X2Z1) + t2.Mul(&L, &a.Y) + J.Mul(&a.X, &O). + Sub(&J, &t2) + + // Line evaluation + evaluations.r0.Set(&L) + evaluations.r1.Neg(&O) + evaluations.r2.Set(&J) +} diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/ecc.go b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.go index 7f5e531c030..5fa1bd961bb 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/ecc.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.go @@ -14,20 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package ecc provides bls12-381, bls12-377, bn254, bw6-761, bls24-315 and bw6-633 elliptic curves implementation (+pairing). +// Package ecc provides bls12-381, bls12-377, bls12-378, bn254, bw6-761, bls24-315, bls24-317, bw6-633, bls12-378, bw6-756, secp256k1 and stark-curve elliptic curves implementation (+pairing). // // Also // -// * Multi exponentiation -// * FFT -// * Polynomial commitment schemes -// * MiMC -// * twisted edwards "companion curves" -// * EdDSA (on the "companion" twisted edwards curves) +// - Multi exponentiation +// - FFT +// - Polynomial commitment schemes +// - MiMC +// - twisted edwards "companion curves" +// - EdDSA (on the "companion" twisted edwards curves) package ecc import ( "math/big" + "strings" "github.com/consensys/gnark-crypto/internal/generator/config" ) @@ -40,81 +41,79 @@ const ( UNKNOWN ID = iota BN254 BLS12_377 + BLS12_378 BLS12_381 BLS24_315 + BLS24_317 BW6_761 BW6_633 + BW6_756 + STARK_CURVE + SECP256K1 ) // Implemented return the list of curves fully implemented in gnark-crypto func Implemented() []ID { - return []ID{BN254, BLS12_377, BLS12_381, BW6_761, BLS24_315} + return []ID{BN254, BLS12_377, BLS12_381, BW6_761, BLS24_315, BW6_633, BLS12_378, BW6_756, BLS24_317, STARK_CURVE, SECP256K1} } func (id ID) String() string { - // TODO link with config.XXX.Name ? - switch id { - case BLS12_377: - return "bls12_377" - case BLS12_381: - return "bls12_381" - case BN254: - return "bn254" - case BW6_761: - return "bw6_761" - case BW6_633: - return "bw6_633" - case BLS24_315: - return "bls24_315" - default: - panic("unimplemented ecc ID") - } + cfg := id.config() + return strings.ToLower(cfg.EnumID) +} + +// ScalarField returns the scalar field of the curve +func (id ID) ScalarField() *big.Int { + cfg := id.config() + return modulus(cfg, true) } -// Info returns constants related to a curve -func (id ID) Info() Info { +// BaseField returns the base field of the curve +func (id ID) BaseField() *big.Int { + cfg := id.config() + return modulus(cfg, false) +} + +func (id ID) config() *config.Curve { // note to avoid circular dependency these are hard coded // values are checked for non regression in code generation switch id { case BLS12_377: - return newInfo(&config.BLS12_377) + return &config.BLS12_377 + case BLS12_378: + return &config.BLS12_378 case BLS12_381: - return newInfo(&config.BLS12_381) + return &config.BLS12_381 case BN254: - return newInfo(&config.BN254) + return &config.BN254 case BW6_761: - return newInfo(&config.BW6_761) + return &config.BW6_761 case BW6_633: - return newInfo(&config.BW6_633) + return &config.BW6_633 case BLS24_315: - return newInfo(&config.BLS24_315) + return &config.BLS24_315 + case BLS24_317: + return &config.BLS24_317 + case BW6_756: + return &config.BW6_756 + case STARK_CURVE: + return &config.STARK_CURVE + case SECP256K1: + return &config.SECP256K1 default: panic("unimplemented ecc ID") } } -func newInfo(c *config.Curve) Info { - return Info{ - Fp: config.Field{ - Bits: c.FpInfo.Bits, - Bytes: c.FpInfo.Bytes, - Modulus: func() *big.Int { return new(big.Int).Set(c.FpInfo.Modulus()) }, - }, - Fr: config.Field{ - Bits: c.FrInfo.Bits, - Bytes: c.FrInfo.Bytes, - Modulus: func() *big.Int { return new(big.Int).Set(c.FrInfo.Modulus()) }, - }, +func modulus(c *config.Curve, scalarField bool) *big.Int { + if scalarField { + return new(big.Int).Set(c.FrInfo.Modulus()) } -} -// Info contains constants related to a curve -type Info struct { - Fp, Fr config.Field + return new(big.Int).Set(c.FpInfo.Modulus()) } // MultiExpConfig enables to set optional configuration attribute to a call to MultiExp type MultiExpConfig struct { - NbTasks int // go routines to be used in the multiexp. can be larger than num cpus. - ScalarsMont bool // indicates if the scalars are in montgommery form. Default to false. + NbTasks int // go routines to be used in the multiexp. can be larger than num cpus. } diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/ecc.md b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.md index b394e4d728a..f4508d76108 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/ecc.md +++ b/vendor/github.com/consensys/gnark-crypto/ecc/ecc.md @@ -6,6 +6,9 @@ * BW6-761 (EC supporting pairing on BLS12-377 field of definition) * BLS24-315 * BW6-633 (EC supporting pairing on BLS24-315 field of definition) +* BLS12-378 (GT-strong SNARK-friendly) +* BW6-756 (EC supporting pairing on BLS12-378 field of definition) +* STARK (STARK curve for ECDSA) ### Twisted edwards curves diff --git a/vendor/github.com/consensys/gnark-crypto/ecc/utils.go b/vendor/github.com/consensys/gnark-crypto/ecc/utils.go index aca2d8e3fa9..78126fc1cc9 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/utils.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/utils.go @@ -1,8 +1,6 @@ package ecc import ( - "crypto/sha256" - "errors" "math/big" "math/bits" ) @@ -54,12 +52,12 @@ func NafDecomposition(a *big.Int, result []int8) int { // Lattice represents a Z module spanned by V1, V2. // det is the associated determinant. type Lattice struct { - V1, V2 [2]big.Int - Det big.Int + V1, V2 [2]big.Int + Det, b1, b2 big.Int } // PrecomputeLattice res such that res.V1, res.V2 -// are short vectors satisfying v11+v12lambda=v21+v22lambda=0[r]. +// are short vectors satisfying v11+v12.λ=v21+v22.λ=0[r]. // cf https://www.iacr.org/archive/crypto2001/21390189.pdf func PrecomputeLattice(r, lambda *big.Int, res *Lattice) { @@ -126,21 +124,31 @@ func PrecomputeLattice(r, lambda *big.Int, res *Lattice) { tmp[0].Mul(&res.V1[1], &res.V2[0]) res.Det.Mul(&res.V1[0], &res.V2[1]).Sub(&res.Det, &tmp[0]) + // sets roundings of 2^n*v21/d and 2^n*v11/d (where 2ⁿ > d) + n := 2 * uint(((res.Det.BitLen()+32)>>6)<<6) + res.b1.Lsh(&res.V2[1], n) + rounding(&res.b1, &res.Det, &res.b1) + res.b2.Lsh(&res.V1[1], n) + rounding(&res.b2, &res.Det, &res.b2) } // SplitScalar outputs u,v such that u+vlambda=s[r]. // The method is to view s as (s,0) in ZxZ, and find a close // vector w of (s,0) in , where l is a sub Z-module of -// ker((a,b)->a+blambda[r]): then (u,v)=w-(s,0), and -// u+vlambda=s[r]. +// ker((a,b) → a+b.λ[r]): then (u,v)=w-(s,0), and +// u+v.λ=s[r]. // cf https://www.iacr.org/archive/crypto2001/21390189.pdf func SplitScalar(s *big.Int, l *Lattice) [2]big.Int { var k1, k2 big.Int - k1.Mul(s, &l.V2[1]) - k2.Mul(s, &l.V1[1]).Neg(&k2) - rounding(&k1, &l.Det, &k1) - rounding(&k2, &l.Det, &k2) + k1.Mul(s, &l.b1) + k2.Mul(s, &l.b2).Neg(&k2) + // right-shift instead of division by lattice determinant + // this increases the bounds on k1 and k2 by 1 + // but we check this ScalarMultiplication alg. (not constant-time) + n := 2 * uint(((l.Det.BitLen()+32)>>6)<<6) + k1.Rsh(&k1, n) + k2.Rsh(&k2, n) v := getVector(l, &k1, &k2) v[0].Sub(s, &v[0]) v[1].Neg(&v[1]) @@ -159,7 +167,7 @@ func rounding(n, d, res *big.Int) { } } -// getVector returns axV1 + bxV2 +// getVector returns aV1 + bV2 func getVector(l *Lattice, a, b *big.Int) [2]big.Int { var res [2]big.Int var tmp big.Int @@ -170,87 +178,6 @@ func getVector(l *Lattice, a, b *big.Int) [2]big.Int { return res } -// ExpandMsgXmd expands msg to a slice of lenInBytes bytes. -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5 -// https://tools.ietf.org/html/rfc8017#section-4.1 (I2OSP/O2ISP) -func ExpandMsgXmd(msg, dst []byte, lenInBytes int) ([]byte, error) { - - h := sha256.New() - ell := (lenInBytes + h.Size() - 1) / h.Size() // ceil(len_in_bytes / b_in_bytes) - if ell > 255 { - return nil, errors.New("invalid lenInBytes") - } - if len(dst) > 255 { - return nil, errors.New("invalid domain size (>255 bytes)") - } - sizeDomain := uint8(len(dst)) - - // Z_pad = I2OSP(0, r_in_bytes) - // l_i_b_str = I2OSP(len_in_bytes, 2) - // DST_prime = I2OSP(len(DST), 1) || DST - // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) - h.Reset() - if _, err := h.Write(make([]byte, h.BlockSize())); err != nil { - return nil, err - } - if _, err := h.Write(msg); err != nil { - return nil, err - } - if _, err := h.Write([]byte{uint8(lenInBytes >> 8), uint8(lenInBytes), uint8(0)}); err != nil { - return nil, err - } - if _, err := h.Write(dst); err != nil { - return nil, err - } - if _, err := h.Write([]byte{sizeDomain}); err != nil { - return nil, err - } - b0 := h.Sum(nil) - - // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) - h.Reset() - if _, err := h.Write(b0); err != nil { - return nil, err - } - if _, err := h.Write([]byte{uint8(1)}); err != nil { - return nil, err - } - if _, err := h.Write(dst); err != nil { - return nil, err - } - if _, err := h.Write([]byte{sizeDomain}); err != nil { - return nil, err - } - b1 := h.Sum(nil) - - res := make([]byte, lenInBytes) - copy(res[:h.Size()], b1) - - for i := 2; i <= ell; i++ { - // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) - h.Reset() - strxor := make([]byte, h.Size()) - for j := 0; j < h.Size(); j++ { - strxor[j] = b0[j] ^ b1[j] - } - if _, err := h.Write(strxor); err != nil { - return nil, err - } - if _, err := h.Write([]byte{uint8(i)}); err != nil { - return nil, err - } - if _, err := h.Write(dst); err != nil { - return nil, err - } - if _, err := h.Write([]byte{sizeDomain}); err != nil { - return nil, err - } - b1 = h.Sum(nil) - copy(res[h.Size()*(i-1):h.Size()*i], b1) - } - return res, nil -} - // NextPowerOfTwo returns the next power of 2 of n func NextPowerOfTwo(n uint64) uint64 { c := bits.OnesCount64(n) diff --git a/vendor/github.com/consensys/gnark-crypto/field/field.md b/vendor/github.com/consensys/gnark-crypto/field/field.md deleted file mode 100644 index 4e9648ceb83..00000000000 --- a/vendor/github.com/consensys/gnark-crypto/field/field.md +++ /dev/null @@ -1,48 +0,0 @@ - -# Usage - -At the root of your repo: -```bash -go get github.com/consensys/gnark-crypto/field -``` - -then in a `main.go` (that can be called using a `go:generate` workflow): - -``` -generator.GenerateFF(packageName, structName, modulus, destinationPath, false) -``` - -The generated type has an API that's similar with `big.Int` - -Example API signature -```go -// Mul z = x * y mod q -func (z *Element) Mul(x, y *Element) *Element -``` - -and can be used like so: - -```go -var a, b Element -a.SetUint64(2) -b.SetString("984896738") - -a.Mul(a, b) - -a.Sub(a, a) - .Add(a, b) - .Inv(a) - -b.Exp(b, 42) -b.Neg(b) -``` - -### Build tags - -Generates optimized assembly for `amd64` target. - -For the `Mul` operation, using `ADX` instructions and `ADOX/ADCX` result in a significant performance gain. - -The "default" target `amd64` checks if the running architecture supports these instruction, and reverts to generic path if not. This check adds a branch and forces the function to reserve some bytes on the frame to store the argument to call `_mulGeneric` . - -This package outputs code that can be compiled with `amd64_adx` flag which omits this check. Will crash if the platform running the binary doesn't support the `ADX` instructions (roughly, before 2016). \ No newline at end of file diff --git a/vendor/github.com/consensys/gnark-crypto/field/generator/config/extension.go b/vendor/github.com/consensys/gnark-crypto/field/generator/config/extension.go new file mode 100644 index 00000000000..53221f89c37 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/field/generator/config/extension.go @@ -0,0 +1,244 @@ +package config + +import "math/big" + +type Element []big.Int + +// Extension is a simple radical extension, obtained by adjoining ⁿ√α to Fp +type Extension struct { + Base *FieldConfig //Fp + Size big.Int //q + Degree int //n such that q = pⁿ TODO: Make uint8 so forced to be positive and small + RootOf int64 //α +} + +func NewTower(base *FieldConfig, degree uint8, rootOf int64) Extension { + ret := Extension{ + Degree: int(degree), + RootOf: rootOf, + Base: base, + } + ret.Size.Exp(base.ModulusBig, big.NewInt(int64(degree)), nil) + return ret +} + +func (f *Extension) FromInt64(i ...int64) Element { + z := make(Element, f.Degree) + for n := 0; n < len(i) && n < int(f.Degree); n++ { + z[n].SetInt64(i[n]) + } + return z +} + +func (f *Extension) Neg(x Element) Element { + z := make(Element, len(x)) + for n := 0; n < len(x); n++ { + z[n].Neg(&x[n]) + } + return z +} + +func max(x int, y int) int { + if x > y { + return x + } + return y +} + +func (f *Extension) Add(x Element, y Element) Element { + z := make(Element, f.Degree) + + for i := 0; i < f.Degree; i++ { + z[i]. + Add(&x[i], &y[i]). + Mod(&z[i], f.Base.ModulusBig) + } + return z +} + +func (f *Extension) Mul(x Element, y Element) Element { + z := make(Element, f.Degree) + maxP := len(x) + len(y) - 2 + alpha := big.NewInt(f.RootOf) + + for p := maxP; p >= 0; p-- { + + var rp big.Int + + for m := max(p-(len(y)-1), 0); m < len(x) && m <= p; m++ { + n := p - m + var prod big.Int + prod.Mul(&x[m], &y[n]) + rp.Add(&rp, &prod) + } + + rI := p % int(f.Degree) //reduced index + + z[rI].Add(&z[rI], &rp).Mod(&z[rI], f.Base.ModulusBig) + + if p >= int(f.Degree) { + z[rI].Mul(&z[rI], alpha) + } + } + + return z +} + +func (f *Extension) MulScalar(c *big.Int, x Element) Element { + z := make(Element, len(x)) + for i := 0; i < len(x); i++ { + f.Base.Mul(&z[i], c, &x[i]) + } + return z +} + +func (f *Extension) Halve(z Element) { + for i := 0; i < len(z); i++ { + if z[i].Bit(0) != 0 { + z[i].Add(&z[i], f.Base.ModulusBig) + } + z[i].Rsh(&z[i], 1) + } +} + +func (f *Extension) reduce(z Element) { + for i := 0; i < len(z); i++ { + z[i].Mod(&z[i], f.Base.ModulusBig) + } +} + +// Sqrt returning √ x, or nil if x is not qr. +func (f *Extension) Sqrt(x Element) Element { + + z := make(Element, f.Degree) + switch f.Degree { + case 1: + if z[0].ModSqrt(&x[0], f.Base.ModulusBig) == nil { + return nil + } + case 2: + // z = z₀ + z₁ i + + if x[0].BitLen() == 0 { + z[1].ModInverse(big.NewInt(f.RootOf), f.Base.ModulusBig).Mul(&z[1], &x[1]) + } + + var discriminant big.Int + z[0].Mul(&x[0], &x[0]) + z[1].Mul(&x[1], &x[1]).Mul(&z[1], big.NewInt(-f.RootOf)) + z[0].Sub(&z[0], &z[1]) + if discriminant.ModSqrt(&z[0], f.Base.ModulusBig) == nil { + return nil + } + z[0].Add(&x[0], &discriminant) + f.Base.halve(&z[0], &z[0]) + if z[0].ModSqrt(&z[0], f.Base.ModulusBig) == nil { + z[0].Sub(&z[0], &discriminant) + if z[0].ModSqrt(&z[0], f.Base.ModulusBig) == nil { + return nil + } + } + z[1].Lsh(&z[0], 1).ModInverse(&z[1], f.Base.ModulusBig).Mul(&z[1], &x[1]) + + default: + panic("only degrees 1 and 2 are supported") + } + + f.reduce(z) + return z +} + +func (f *Extension) ToMont(x Element) Element { + z := make([]big.Int, len(x)) + for i := 0; i < len(x); i++ { + z[i] = f.Base.ToMont(x[i]) + } + return z +} + +func (f *Extension) Equal(x Element, y Element) bool { + if len(x) != len(y) { + return false + } + for i := 0; i < len(x); i++ { + var diff big.Int + if diff.Sub(&x[i], &y[i]).Mod(&diff, f.Base.ModulusBig).BitLen() != 0 { + return false + } + } + return true +} + +func (f *Extension) norm(z *big.Int, x Element) *Extension { + if f.Degree != 2 { + panic("only degree 2 supported") + } + var x0Sq big.Int + + x0Sq.Mul(&x[0], &x[0]) + + res := big.NewInt(-f.RootOf) + res.Mul(res, &x[1]).Mul(res, &x[1]).Add(res, &x0Sq) + + z.Set(res) + + return f +} + +func (f *Extension) Inverse(x Element) Element { + z := make(Element, f.Degree) + switch f.Degree { + case 1: + z[0].ModInverse(&x[0], f.Base.ModulusBig) + case 2: + var normInv big.Int + f.norm(&normInv, x) + normInv.ModInverse(&normInv, f.Base.ModulusBig) + z[0].Mul(&x[0], &normInv) + + z[1].Neg(&x[1]).Mul(&z[1], &normInv) + default: + panic("can't invert in extensions of degree > 2") + } + return z +} + +func (f *Extension) Exp(x Element, exp *big.Int) Element { + + if exp.BitLen() == 0 { + return f.FromInt64(1) + } + + z := x + + for i := exp.BitLen() - 2; i >= 0; i-- { + z = f.Mul(z, z) + if exp.Bit(i) == 1 { + z = f.Mul(z, x) + } + } + + return z +} + +// Div returns u/v +func (f *Extension) Div(u, v Element) Element { + return f.Mul(u, f.Inverse(v)) +} + +func (f *Extension) IsZero(u Element) bool { + for i := 0; i < len(u); i++ { + if u[i].BitLen() != 0 { + return false + } + } + return true +} + +func NewElement(s []string) []big.Int { + res := make([]big.Int, len(s)) + for i, S := range s { + res[i].SetString(S, 0) + } + return res +} diff --git a/vendor/github.com/consensys/gnark-crypto/field/field.go b/vendor/github.com/consensys/gnark-crypto/field/generator/config/field_config.go similarity index 55% rename from vendor/github.com/consensys/gnark-crypto/field/field.go rename to vendor/github.com/consensys/gnark-crypto/field/generator/config/field_config.go index 5d521f9415a..457a89d7d2e 100644 --- a/vendor/github.com/consensys/gnark-crypto/field/field.go +++ b/vendor/github.com/consensys/gnark-crypto/field/generator/config/field_config.go @@ -12,78 +12,83 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package field provides Golang code generation for efficient field arithmetic operations. -package field +// Package config provides Golang code generation for efficient field arithmetic operations. +package config import ( "errors" + "fmt" + "math" "math/big" + "strconv" + "strings" - "github.com/consensys/gnark-crypto/field/internal/addchain" + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/field/generator/internal/addchain" ) var ( - errUnsupportedModulus = errors.New("unsupported modulus. goff only works for prime modulus w/ size > 64bits") - errParseModulus = errors.New("can't parse modulus") + errParseModulus = errors.New("can't parse modulus") ) -// Field precomputed values used in template for code generation of field element APIs -type Field struct { - PackageName string - ElementName string - ModulusBig *big.Int - Modulus string - ModulusHex string - NbWords int - NbBits int - NbWordsLastIndex int - NbWordsIndexesNoZero []int - NbWordsIndexesFull []int - NbWordsIndexesNoLast []int - NbWordsIndexesNoZeroNoLast []int - P20InversionCorrectiveFac []uint64 - P20InversionNbIterations int - Q []uint64 - QInverse []uint64 - QMinusOneHalvedP []uint64 // ((q-1) / 2 ) + 1 - ASM bool - RSquare []uint64 - One []uint64 - LegendreExponent string // big.Int to base16 string - NoCarry bool - NoCarrySquare bool // used if NoCarry is set, but some op may overflow in square optimization - SqrtQ3Mod4 bool - SqrtAtkin bool - SqrtTonelliShanks bool - SqrtE uint64 - SqrtS []uint64 - SqrtAtkinExponent string // big.Int to base16 string - SqrtSMinusOneOver2 string // big.Int to base16 string - SqrtQ3Mod4Exponent string // big.Int to base16 string - SqrtG []uint64 // NonResidue ^ SqrtR (montgomery form) - NonResidue []uint64 // (montgomery form) - LegendreExponentData *addchain.AddChainData - SqrtAtkinExponentData *addchain.AddChainData - SqrtSMinusOneOver2Data *addchain.AddChainData - SqrtQ3Mod4ExponentData *addchain.AddChainData - UseAddChain bool +// FieldConfig precomputed values used in template for code generation of field element APIs +type FieldConfig struct { + PackageName string + ElementName string + ModulusBig *big.Int + Modulus string + ModulusHex string + NbWords int + NbBits int + NbBytes int + NbWordsLastIndex int + NbWordsIndexesNoZero []int + NbWordsIndexesFull []int + P20InversionCorrectiveFac []uint64 + P20InversionNbIterations int + UsingP20Inverse bool + IsMSWSaturated bool // indicates if the most significant word is 0xFFFFF...FFFF + Q []uint64 + QInverse []uint64 + QMinusOneHalvedP []uint64 // ((q-1) / 2 ) + 1 + ASM bool + RSquare []uint64 + One, Thirteen []uint64 + LegendreExponent string // big.Int to base16 string + NoCarry bool + NoCarrySquare bool // used if NoCarry is set, but some op may overflow in square optimization + SqrtQ3Mod4 bool + SqrtAtkin bool + SqrtTonelliShanks bool + SqrtE uint64 + SqrtS []uint64 + SqrtAtkinExponent string // big.Int to base16 string + SqrtSMinusOneOver2 string // big.Int to base16 string + SqrtQ3Mod4Exponent string // big.Int to base16 string + SqrtG []uint64 // NonResidue ^ SqrtR (montgomery form) + NonResidue big.Int // (montgomery form) + LegendreExponentData *addchain.AddChainData + SqrtAtkinExponentData *addchain.AddChainData + SqrtSMinusOneOver2Data *addchain.AddChainData + SqrtQ3Mod4ExponentData *addchain.AddChainData + UseAddChain bool } -// NewField returns a data structure with needed information to generate apis for field element +// NewFieldConfig returns a data structure with needed information to generate apis for field element // // See field/generator package -func NewField(packageName, elementName, modulus string, useAddChain bool) (*Field, error) { +func NewFieldConfig(packageName, elementName, modulus string, useAddChain bool) (*FieldConfig, error) { // parse modulus var bModulus big.Int - if _, ok := bModulus.SetString(modulus, 10); !ok { + if _, ok := bModulus.SetString(modulus, 0); !ok { return nil, errParseModulus } // field info - F := &Field{ + F := &FieldConfig{ PackageName: packageName, ElementName: elementName, - Modulus: modulus, + Modulus: bModulus.Text(10), ModulusHex: bModulus.Text(16), ModulusBig: new(big.Int).Set(&bModulus), UseAddChain: useAddChain, @@ -91,14 +96,13 @@ func NewField(packageName, elementName, modulus string, useAddChain bool) (*Fiel // pre compute field constants F.NbBits = bModulus.BitLen() F.NbWords = len(bModulus.Bits()) - if F.NbWords < 2 { - return nil, errUnsupportedModulus - } + F.NbBytes = F.NbWords * 8 // (F.NbBits + 7) / 8 F.NbWordsLastIndex = F.NbWords - 1 // set q from big int repr F.Q = toUint64Slice(&bModulus) + F.IsMSWSaturated = F.Q[len(F.Q)-1] == math.MaxUint64 _qHalved := big.NewInt(0) bOne := new(big.Int).SetUint64(1) _qHalved.Sub(&bModulus, bOne).Rsh(_qHalved, 1).Add(_qHalved, bOne) @@ -128,6 +132,11 @@ func NewField(packageName, elementName, modulus string, useAddChain bool) (*Fiel p20InversionCorrectiveFac.Mod(p20InversionCorrectiveFac, &bModulus) F.P20InversionCorrectiveFac = toUint64Slice(p20InversionCorrectiveFac, F.NbWords) + { + c := F.NbWords * 64 + F.UsingP20Inverse = F.NbWords > 1 && F.NbBits < c + } + // rsquare _rSquare := big.NewInt(2) exponent := big.NewInt(int64(F.NbWords) * 64 * 2) @@ -139,22 +148,21 @@ func NewField(packageName, elementName, modulus string, useAddChain bool) (*Fiel one.Lsh(&one, uint(F.NbWords)*64).Mod(&one, &bModulus) F.One = toUint64Slice(&one, F.NbWords) + { + var n big.Int + n.SetUint64(13) + n.Lsh(&n, uint(F.NbWords)*64).Mod(&n, &bModulus) + F.Thirteen = toUint64Slice(&n, F.NbWords) + } + // indexes (template helpers) F.NbWordsIndexesFull = make([]int, F.NbWords) F.NbWordsIndexesNoZero = make([]int, F.NbWords-1) - F.NbWordsIndexesNoLast = make([]int, F.NbWords-1) - F.NbWordsIndexesNoZeroNoLast = make([]int, F.NbWords-2) for i := 0; i < F.NbWords; i++ { F.NbWordsIndexesFull[i] = i if i > 0 { F.NbWordsIndexesNoZero[i-1] = i } - if i != F.NbWords-1 { - F.NbWordsIndexesNoLast[i] = i - if i > 0 { - F.NbWordsIndexesNoZeroNoLast[i-1] = i - } - } } // See https://hackmd.io/@gnark/modular_multiplication @@ -236,8 +244,7 @@ func NewField(packageName, elementName, modulus string, useAddChain bool) (*Fiel F.SqrtG = toUint64Slice(&g, F.NbWords) // store non residue in montgomery form - nonResidue.Lsh(&nonResidue, uint(F.NbWords)*64).Mod(&nonResidue, &bModulus) - F.NonResidue = toUint64Slice(&nonResidue) + F.NonResidue = F.ToMont(nonResidue) // (s+1) /2 s.Sub(&s, &one).Rsh(&s, 1) @@ -252,7 +259,7 @@ func NewField(packageName, elementName, modulus string, useAddChain bool) (*Fiel // note: to simplify output files generated, we generated ASM code only for // moduli that meet the condition F.NoCarry // asm code generation for moduli with more than 6 words can be optimized further - F.ASM = F.NoCarry && F.NbWords <= 12 + F.ASM = F.NoCarry && F.NbWords <= 12 && F.NbWords > 1 return F, nil } @@ -303,3 +310,125 @@ func extendedEuclideanAlgo(r, q, rInv, qInv *big.Int) { } qInv.Neg(qInv) } + +// StringToMont takes an element written in string form, and returns it in Montgomery form +// Useful for hard-coding in implementation field elements from standards documents +func (f *FieldConfig) StringToMont(str string) big.Int { + + var i big.Int + i.SetString(str, 0) + i = f.ToMont(i) + + return i +} + +func (f *FieldConfig) ToMont(nonMont big.Int) big.Int { + var mont big.Int + mont.Lsh(&nonMont, uint(f.NbWords)*64) + mont.Mod(&mont, f.ModulusBig) + return mont +} + +func (f *FieldConfig) FromMont(nonMont *big.Int, mont *big.Int) *FieldConfig { + + if f.NbWords == 0 { + nonMont.SetInt64(0) + return f + } + f.halve(nonMont, mont) + for i := 1; i < f.NbWords*64; i++ { + f.halve(nonMont, nonMont) + } + + return f +} + +func (f *FieldConfig) Exp(res *big.Int, x *big.Int, pow *big.Int) *FieldConfig { + res.SetInt64(1) + + for i := pow.BitLen() - 1; ; { + + if pow.Bit(i) == 1 { + res.Mul(res, x) + } + + if i == 0 { + break + } + i-- + + res.Mul(res, res).Mod(res, f.ModulusBig) + } + + res.Mod(res, f.ModulusBig) + return f +} + +func (f *FieldConfig) halve(res *big.Int, x *big.Int) { + var z big.Int + if x.Bit(0) == 0 { + z.Set(x) + } else { + z.Add(x, f.ModulusBig) + } + res.Rsh(&z, 1) +} + +func (f *FieldConfig) Mul(z *big.Int, x *big.Int, y *big.Int) *FieldConfig { + z.Mul(x, y).Mod(z, f.ModulusBig) + return f +} + +func (f *FieldConfig) Add(z *big.Int, x *big.Int, y *big.Int) *FieldConfig { + z.Add(x, y).Mod(z, f.ModulusBig) + return f +} + +func (f *FieldConfig) ToMontSlice(x []big.Int) []big.Int { + z := make(Element, len(x)) + for i := 0; i < len(x); i++ { + z[i] = f.ToMont(x[i]) + } + return z +} + +// TODO: Spaghetti Alert: Okay to have codegen functions here? +func CoordNameForExtensionDegree(degree uint8) string { + switch degree { + case 1: + return "" + case 2: + return "A" + case 6: + return "B" + case 12: + return "C" + } + panic(fmt.Sprint("unknown extension degree", degree)) +} + +func (f *FieldConfig) WriteElement(element Element) string { + var builder strings.Builder + + builder.WriteString("{") + length := len(element) + var subElementNames string + if length > 1 { + builder.WriteString("\n") + subElementNames = CoordNameForExtensionDegree(uint8(length)) + } + for i, e := range element { + if length > 1 { + builder.WriteString(subElementNames) + builder.WriteString(strconv.Itoa(i)) + builder.WriteString(": fp.Element{") + } + mont := f.ToMont(e) + bavard.WriteBigIntAsUint64Slice(&builder, &mont) + if length > 1 { + builder.WriteString("},\n") + } + } + builder.WriteString("}") + return builder.String() +} diff --git a/vendor/github.com/consensys/gnark-crypto/field/internal/addchain/addchain.go b/vendor/github.com/consensys/gnark-crypto/field/generator/internal/addchain/addchain.go similarity index 99% rename from vendor/github.com/consensys/gnark-crypto/field/internal/addchain/addchain.go rename to vendor/github.com/consensys/gnark-crypto/field/generator/internal/addchain/addchain.go index 408c26cf759..7dd42b1837c 100644 --- a/vendor/github.com/consensys/gnark-crypto/field/internal/addchain/addchain.go +++ b/vendor/github.com/consensys/gnark-crypto/field/generator/internal/addchain/addchain.go @@ -62,7 +62,7 @@ var ( mAddchains map[string]*AddChainData // key is big.Int.Text(16) ) -// GetAddChain retunrs template data of a short addition chain for given big.Int +// GetAddChain returns template data of a short addition chain for given big.Int func GetAddChain(n *big.Int) *AddChainData { // init the cache only once. diff --git a/vendor/github.com/consensys/gnark-crypto/field/hash/hashutils.go b/vendor/github.com/consensys/gnark-crypto/field/hash/hashutils.go new file mode 100644 index 00000000000..db7cff3e130 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/field/hash/hashutils.go @@ -0,0 +1,94 @@ +package hash + +import ( + "crypto/sha256" + "errors" +) + +// ExpandMsgXmd expands msg to a slice of lenInBytes bytes. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5 +// https://tools.ietf.org/html/rfc8017#section-4.1 (I2OSP/O2ISP) +func ExpandMsgXmd(msg, dst []byte, lenInBytes int) ([]byte, error) { + + h := sha256.New() + ell := (lenInBytes + h.Size() - 1) / h.Size() // ceil(len_in_bytes / b_in_bytes) + if ell > 255 { + return nil, errors.New("invalid lenInBytes") + } + if len(dst) > 255 { + return nil, errors.New("invalid domain size (>255 bytes)") + } + sizeDomain := uint8(len(dst)) + + // Z_pad = I2OSP(0, r_in_bytes) + // l_i_b_str = I2OSP(len_in_bytes, 2) + // DST_prime = I2OSP(len(DST), 1) ∥ DST + // b₀ = H(Z_pad ∥ msg ∥ l_i_b_str ∥ I2OSP(0, 1) ∥ DST_prime) + h.Reset() + if _, err := h.Write(make([]byte, h.BlockSize())); err != nil { + return nil, err + } + if _, err := h.Write(msg); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(lenInBytes >> 8), uint8(lenInBytes), uint8(0)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b0 := h.Sum(nil) + + // b₁ = H(b₀ ∥ I2OSP(1, 1) ∥ DST_prime) + h.Reset() + if _, err := h.Write(b0); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(1)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 := h.Sum(nil) + + res := make([]byte, lenInBytes) + copy(res[:h.Size()], b1) + + for i := 2; i <= ell; i++ { + // b_i = H(strxor(b₀, b_(i - 1)) ∥ I2OSP(i, 1) ∥ DST_prime) + h.Reset() + strxor := make([]byte, h.Size()) + for j := 0; j < h.Size(); j++ { + strxor[j] = b0[j] ^ b1[j] + } + if _, err := h.Write(strxor); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(i)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 = h.Sum(nil) + copy(res[h.Size()*(i-1):min(h.Size()*i, len(res))], b1) + } + return res, nil +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/vendor/github.com/consensys/gnark-crypto/field/pool/pool.go b/vendor/github.com/consensys/gnark-crypto/field/pool/pool.go new file mode 100644 index 00000000000..6bb10bdbdc6 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/field/pool/pool.go @@ -0,0 +1,28 @@ +package pool + +import ( + "math/big" + "sync" +) + +// BigInt is a shared *big.Int memory pool +var BigInt bigIntPool + +var _bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +type bigIntPool struct{} + +func (bigIntPool) Get() *big.Int { + return _bigIntPool.Get().(*big.Int) +} + +func (bigIntPool) Put(v *big.Int) { + if v == nil { + return // see https://github.com/ConsenSys/gnark-crypto/issues/316 + } + _bigIntPool.Put(v) +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-377.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-377.go index 4416e2a60ea..62bb79b0719 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-377.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-377.go @@ -8,6 +8,7 @@ var BLS12_377 = Curve{ FpModulus: "258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", G1: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g1", GLV: true, CofactorCleaning: true, @@ -15,15 +16,307 @@ var BLS12_377 = Curve{ }, G2: Point{ CoordType: "fptower.E2", + CoordExtDegree: 2, + CoordExtRoot: -5, PointName: "g2", GLV: true, CofactorCleaning: true, CRange: defaultCRange(), Projective: true, }, + // 2-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0x1ae3a4617c510ea34b3c4687866d1616212919cefb9b37e860f40fde03873fc0a0bf847bffffff8b9857ffffffffff2"}, + B: []string{"0x16"}, + Z: []int{5}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x142abb491d3ccb00d65810beba93dbb0a661fd85974d6aa82c4bb2e1a3c84ffdd6ef419b80000000000000000000000"}, + {"0x4d9d782ee8a7b7630cd57be9a2ca555e2f689a3cb86f60022910be6480000004284600000000001"}, + {"0x142abb491d3ccb014ac44505178f6ec539a237640b7ceab573689a3cb86f600114885f32400000063c6900000000001"}, + }, + Den: [][]string{ + {"0x13675e0bba29edd8c3355efa68b295578bda268f2e1bd8008a442f99200000010a11800000000004"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x142abb491d3ccb014ac44505178f6ec539a237640b7ceab573689a3cb86f600114885f32400000063c68fffffffffff"}, + {"0x35c748c2f8a21d6af848e30c1b78229a46644922460e73f6faf06c327b438084815848140000010a11800000000002"}, + {"0xd71d230be288756a6446249c205dced645709767bd81c863eb7f8d8e4f15003f5f407b84000000a64af00000000002"}, + {"0x17872fd54cc6ecd6d73a5085f0d2013b6de7eb4a0d6711d3b14f5e9c2c81f001429f19baa0000007467a80000000001"}, + }, + Den: [][]string{ + {"0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508bffffffffff9"}, + {"0x746c34465cfb9314934039de742f800d471ce75b14a710033d991d96c00000063c6900000000000c"}, + {"0x3a361a232e7dc98a49a01cef3a17c006a38e73ad8a5388019ecc8ecb600000031e3480000000000c"}, + }, + }, + }, + }, + + // 23-isogeny + HashE2: &HashSuiteSswu{ + A: []string{"0x152964189f4c623685ae0423eb10294ce6458c064f093208504005b37d04d5d336dc9d66a97093f84d62e778f8c82be", "0x735c455387ab435839e5a5dbc1a30510070300f4becac797642fe56985064e95f7d6521a1a6e71004047f835c1f957"}, + B: []string{"0x19e38372e0d4bf401d2fa5f2261e1e3fc95d51a3857fc23b1385d51ea9c973a89c22148a93dff96447700bf1c3aebac", "0x1579ddb5c1c595b7c08c3a3cef5626143c25757c6b67d0a2677b22fc0c890d8b2b1a17895d047a98c49047069f725"}, + Z: []int{12, 1}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x113b0abb7ba48832ffb7aaaa7ce085078312d4bf0bf8882e8f4a0a6e24d91b535b6c81277ad9369cacc733de5cf86d9", + "0x11e62d211119d8108bbf13b3b4b79a1aabbe2d6004858109139667b300e5097370015d42782ca1bf7652dba1d4cac3c"}, + {"0x51a19546efd3c582ec16ee049bafb8ccbdd87d98f753e654e0b93ae62a627a6f610b30f76016baa8d18dc4677dc401", + "0xddc3aac50aa5af86f8c1d31db787f4b6ac0262a8ea40c07d61389c2a70b06c51fb59520394e05c55c72e363b9607a1"}, + {"0x93198927f09c55a596756ab909a06ab3c0127be6538fb275f2b7b5bfaa1ab85b12a45ef345d628d5c6e69effd7e76a", + "0x2c02fb38b1440c7b2d4fae061763cd734c40b1eddf1ca9552554d2859906f8d6290038a485a655f8178f99b1fe43e1"}, + {"0x19091208a40d61bd9a55359da28b532617da69a58addac35288930ccd5083166d791cc7dd3c6533e01f786000c532f7", + "0xcf913d369130273a81f982f469bc8fd98a8983af247d28845d76729468a777836e1d3cdf1e1adea6b08566db5b514f"}, + {"0x181a36b975099a83b4773c6e62d93365d5fd3787c2b62d0a315245f6226ab13cd462f731b73a436a598b34dc0ec58d0", + "0xdeebd58f0234fa272439c69d9f0ed559b955d416256645c2ab1857d988b49109ff460206e2b978d877fc9274fe4840"}, + {"0x10cd4f85b581fa9bbd614f001a2e64839a4635373187b57373f17f77e11ea30ce505e6ebab860ee2aa46c9e6b327add", + "0xc1f11111a68f3346dfeb807985c61491498efd3439c5c7a0b77e9d819a48be950e43c9f30cd21e5e439815a2ab6a9a"}, + {"0x1813ccf2b39896b88561d57592c5e7d7594146f9eb341852cdbc192e88792058059bd79b248c5b8c415d6149d51130a", + "0xeb958c5ed40e2b75a170536e42368207df82fcc26518f6f83f40cea65efdd81dcc248290c660107e0a2d650a38d526"}, + {"0xa143ff2d94ba2d2322d63cb3769874b17c00fe76fff4b53fb5fa4744da3114899adaca240bde7d88357aa80b144bb1", + "0xa25054cd91b2b06cdad439cdf86265929d35738f09e759a56164861f45586602c630ef182e9262f0413374b154dd20"}, + {"0x1f0a897c94b01589c9eb5cdd999c580c284f39c6fa6f2ad0c569c3b219cc245484ed7310b858f980b2917508d94f59", + "0x5c56eb37beca858c993f39fbf09b73efbd98934b5b1d8de0c21fc75d20075e6d7720601832565b1823339bffc17a6d"}, + {"0x13a21ac110c90240e49de23070e86bcb64b8c500d8f9d792095a0a7f9133f4d8d94c518f9eb1359c8c82926e41d004c", + "0x18471a982b5d8d7756ff4971fbba3945be37cea5cda74e17674b76cbf527f8ae51a27236a95d815a4f36a2461df5b67"}, + {"0x380e386dce2ad72755e1d21461a3d33ce275b036c2a11a755df7e948161f3318531311b8dfaad26a2b6af699e42f07", + "0xc86f279fd500d0594160f87a462ff89f4b0db7b7fe6bc809871f11183f13235d343e0a8bae13c9f5791a2821ce8bf"}, + {"0xd73c34c8f904e327cd1fc22e8a90e04bed13e46eb98e3d47d18cde142b9e0f3a03eaac69214acac03042aa9b9b6495", + "0x76ea3cf6b7185d7d6e3e73ac03a21b645e5aaee7a99dccecc485620fdf64e7486c7b1e4f8b6e069240b7a1e76b0609"}, + {"0xca983f9f6ea728c5b4bb9a6dc72d24ecab7833e1a8242bf1a84140deb996176a8f7c7d6fe34fdb4660afd6dfa5fd74", + "0x7e4badbdba86487f1b87daccf8d14f62bcb01bca058d8e318ad40ae8343a47d40f6b18af1e0bf9860eeb32db4f02aa"}, + {"0x1552beaa2371b711181b528b4ea3e801e3a71c2bc0bde70a2babef6d5702ff12af4f5f2823599093d5485b94c873d36", + "0x11783b91dc5ce3d03283278116bb901408dc61ef8bad40991144de2f3509787d83b566820fd315b558ccd76c9debd5d"}, + {"0x175374ccff26ce81965dce12856efd5cb587251e70a588e2e4633110d65bf17f2991df664e727ebc65b42d74a938e4b", + "0xe75b2e26120b6428e51285251602a89ca9f865d444853ac3527b940d7b218df89806e725ec52e75b92dfcf63616483"}, + {"0xecfa3729a48226a477e72d4067aa372a29fa8943324495f2f39f754bd1d114fc2d9c62453fde06e3272bf09faea06f", + "0xe95c673c49bda6dacee18f07327cee3902582326fbe658d3e8cb15b40327b8b7c1b04e0160071f1e8c617361754705"}, + {"0x155dd556a15b55b766cc98f3455788f3ca450ac5c613b2e1464b53f0e5412a626e423cf9dd5127edaa6deeaa5638f93", + "0x15ac434170f220d28273b44c48eca01f2cfaae20e2342429ca6f3668e0825821a3d7f1227db23b1a7a36e7f8abf89e"}, + {"0xe785dde291472723e95d737c7bc0bb72a8125cfbd91b122beedd3f45dedefc1480e9350bbfb6a5ca2fb9ec905573fa", + "0xe01e2c8ab4ddf439c8d4028ccc68b13de8099e3aa7d5120867366605682a4db4ec308cf07e043cf7256e35c23ecbc7"}, + {"0x4e2c05f403fa31d03e91053fb52a3fc12ae58977575f53cd8a52b53d1067cc61de65daada7c7c1bf5bdb07f3719b14", + "0x18de34a92f81eba3a57d55a9d4bd5cf7da7b1794a0f9ece37abd537ddcdb29edbb01aa88baef416408d34a227874c33"}, + {"0xe4a28f5d9cdcb181099868140cf3064cd573f892aceb79e3df63546686df19a3164efedc851333bbe232be84e3e627", + "0xd31f8027ef5f6b916364d998dbc4640196191cf0ca44e2c2c4825bf4babd706351d21f1f6177ee4c3f5d16928d059b"}, + {"0x602985c2bf7472638e59af721dc3e635d08ede15ad23084d54441a493d515ab9d727832a06110b8a5e4cdf978980d1", + "0x159cb19fac8df89c704efce7423d8965e1477606471d21f77988cd744d0ea0938a85eb4a21d41a34c97d64a409f7314"}, + {"0x12f6020b2f6dc691f96e6a7c5e42a221a861c1b27223e30adbb75022ff42f318e8d96e0a964dfcb9dd0d20fd3a7c247", + "0x1766ffa6c449787005d03e90251c271190a3c8e6db8383ce2925b91c87ae29c989d503705ed7566fe5c7bfefb6902c6"}, + {"0x471dda72677bf4df7027fff15bb88083362b56b41dbbeb3e3f9afed6c7fd9b8e03a7b66f7dde784cdb94ef12714ed1", + "0xb95429ba2726547f58f812d8516a9c7545fb43d2080d1b154e4e8aaa689a378141fd28ad946cf12fef100e180c9762"}, + {"0x1ac99df3bf98db5235d2892b0f00a86db204cc8f367535d37ff878fd945bcd6f4991d08e3d7598788e2f860c950d110", + "0x0"}, + }, + Den: [][]string{ + {"0x146e50faa64a7651c3b0b61836501a66805927dcb051b32662d0d261c3b5458776918917726e7ab20050fb3f1e9d32c", + "0xb1ea777f7008d8bcafa4799bac2e33475d6b287b6c831af5c06bb778507412d8aa8d347a14ea074b7983518d668616"}, + {"0x79f0dba8c34b89c8d1fd2363421e1f97f7f12579ab42f520b86c9e7b44e822fadf62f6e98bfebed3065ef7e6d873e2", + "0x40dd9ff7e21f5f6802ef1e47c240880f84fbe0232f659145f22f9c842736890572e9a0018ff427005b45140ad2597d"}, + {"0xde82c1e45e55039d5d8ae4684e278f230e94285b4bc97eae01f84acf258e9be8888a96dd0fdccde825922ec5517ec5", + "0x101b161db02dadd38c1b219d253f01728d2b3ba65e3dc05ebf102ff9fab2f2ef1cc95047570148228b4915820b0301d"}, + {"0x19c6b7b7a90b244a9cc8e9cf77c1fc40ffeae17efe57efaad45c6b85105effe955b8aec25cd5a33b5fe1b403099cc87", + "0x1658235a28d3dcd62a783eb6e135a65f19ee1ded96bf717f26fb9e81763b6d1d0d32ef686998776504a5c6426ba2ddc"}, + {"0x1374e714d24649d3de48ea7e809ed20ba8de79a7a95b59e26babe22856e57c5f9e6667da8107e27b1215afe2846471", + "0x9fa434f0a714ff9b2bb5ea51856efce45659377666fe4377774d04ca63a1ae957c5cc11376defad113c94ae6ce4652"}, + {"0x11796b770f7504fb0a25336ae91aca083bb600d5523a27885e44f3bedff57966411346d44cce4bbaf50770a210445b7", + "0xa5dc732bb3f95325df484711467e89dc69a7986d2439a692fb9667c22512d87f968d452c1a7a4af94629d6fbfab126"}, + {"0x36fc8fd543e00229e3e56ca9655db01cb161ad493c35d5225acea1924f2673890b0981feb9170a2b73e1ed5852276a", + "0x11e47853a548367d9473b4251c2641a1a05ded1721fb74dfd4455bb41894cd35ffa77ac1a1dda4171e8e3c598cc0cf"}, + {"0xec3aecb4916b2621d73c22adf37fd2bd067cfcd09f38cfa7060c1dc08573f6e6da62ae459d00c719b153b23eb30380", + "0x33b7e5c5174d637291e17246bd01864eaf2b12d27ab74b84e029ed82c9cf3551faa44b79bdbb079a9f57f598e8c35"}, + {"0x14d8b5c3fe739ff9bca51db2433814bd39a0ba8f082801125801599b81682fe51896aeed82936cfc3d7850d2f9622a3", + "0x7adf53096d8b637caa65a6703d654842a9b7d4d82a1ebd6ae4eb4cf7df07912638d359dbfe6f8443fcae492cb150c5"}, + {"0x16e8eda7dfd1927fe1dc22dacaa78237dfa0714315f535e804649326acfe5c67a86dcbee4d78a5d662ff122b8580245", + "0x40de374242af4c470b0952cc13dae780d77d43729e9598ba3173ac586624ebe305c8c9e6e5e7245f98a970af1ee60d"}, + {"0x16c94723b3eacaa13fef87169f4eca0959eecf2184d6a7468da9d8f32acb6a36c5254bf31d733f5b1c053dd88e54282", + "0x19c508401f6e0cdcf9e2b694c12550eba4247c85c52b8aba5991f9aeecbefee61355271663b842b0b23c0de66bcb8f1"}, + {"0xf3ffd87f27eee739719fa368e3d9bebdb8f06a192b5ae980b629ad78421034b2f919d658fbcd1490fc7692e1e916ce", + "0x1468f37ed6477c421170d67235b0370aa3388db7e4c0cb3dbcf1fef55b2c7cd6989451199b411d7aaf8a5b24436f6e3"}, + {"0x1035e4ec93dc6bc358f961e7dc4c82087605cbe2bfdbe713fa5e7b21d75c1ad45088bdbc6daaa2e12d1f0bcfb4b84f7", + "0x11e842bd544d0bbee76808f0a1ba264be31aedda57ceb64330b587d5a89d03598cdb8d2b528fe56a02dbfd48e8aaa83"}, + {"0xe57bf7b799080766c07fa8b997f65da74043a005d785b60215c0875d8d80a2a55de8c81dc081ee75cafdcb6d9f5bab", + "0x4f2c024aca0ee3f8be88ed1450ac2448d3bd8b540d7cb9b5d93d68eedc20119213d260c02c7dbaa180aa008407b0dc"}, + {"0xe0b435cad88cfd17508b5b3da274b76521f715b9129c3141f70a3c7dd22e14c3fe58a5db7c168f47c673d91a05c02f", + "0x16ba8b632d08a5abe396f990cfc790f6d29725220c89e7dacb3be59699757c6245bc0793bfeb5b2f917508cdd949a79"}, + {"0x17c5e37674a25c3385908a02be0a23c1623eb710deb01632301277cb968ae2bccd3e5b38e144e424a9da459c4b8600a", + "0x503556d7e47b59d5888f787cb7cec46d917d02f8118e01a63ffc3b01398260d7c722dc26c7cd03d7c05e1a996e5471"}, + {"0x890e4e58ded34996cf252dc184d7aec1c1866ad2da0b50ffc208a1ef31dd9e277b3f5e2fd1f3cf9422b81c526bbd0d", + "0x108938787e3377815ba98065f7c57b955fb7bc2247a21fd516fcad09652e92819c4bd34cf9be483e261639e540ce577"}, + {"0x665b1acc1e271d15bf9416f014ae1ddc76838a60230be0cd17cc7505d6b5f7cb01037545fd2c3b9997b0745ad8ad9c", + "0x1ae0fc9e185ac85323228f01780e30ba86767c59cc90d2d05ddbba8d6cf35bbd737b7fcd09b3850af513ebb6fc3ced9"}, + {"0x16db2dd779c2cc1699abf727df65339443007994b70c43a8d9767e265dfe45809093cc631ba5b79f1280236ac93fddf", + "0x43671e62ee377b90bbd80c91a3dc1eb53ed37ea8ae6ccc0154e2f1cf498198acc92b2ce3c07e292b2b5f038c6c04c9"}, + {"0x93b2b87c160c52f6b056e4c085930add9aeb706709ee013eb54ca60bc820b0da42fbca8e9c9a579585bdb8af77acbe", + "0xcb5381cf50932ff1dd7fed460732ae9311b24ab543d98304b80963cf706598ef147c2b047d6c2e49357f5704e568ba"}, + {"0x731b19b58014b17a0be1915dfee088ceb8ca7964deed74d985adfbe0e9aa99cac1453ae4210abf949afc9c7425f2b6", + "0x3f906b21602c1254dc293fbddc3974f24bef13d0291760083c7a125c8ad5c49ed9ba755743e9344387d1e712d7ede2"}, + {"0xbee29453de653858b3b37cd3b85e7941177c94de27ab781cb8ea619a1b9668a0b0ddd01318b6699bc582051c23dd8a", + "0x1793e129728346d60828550ad395de628b4f4ab2952bd0e95003c382bebd49daa486d981fb51dee163ded1fb204d09f"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x19474819a519191689e0816c7f84b2a58a6a5aaf5adfd7fb0204d8623f67c19e9a64d522ce4c963e32de8edfd367284", + "0x100e238102de877617418a44564d9379372b6f69c721b205c60af2e298bfa546a7c7a39883e433f947601b24266a306"}, + {"0xb58b352e8f9bc6162e40b4ab27f066cb71ed844e9b5e376cdef8e8be14e38d2f13392f19da19ca1faa758bbb083dc6", + "0x3293cacae9e6251abad8ac4d8263754f1301062d54ff721d183d201f9133db07341cd48c721d8b9ec40e41d4bd0db0"}, + {"0xdfec4d8ecb1cb0adbe13f68ccb2e070bcbf5ee3ee8328cb6613a63a543c252ef4ecb525fbf65ca12f33b425da04d5", + "0x177fa15abb4e47ced85ae0765a6aef971131743de887073556fe92f142b83a8355edc8544530ed7296a3e21c4f9828a"}, + {"0x17bbcf8bf3802b3f868ec94dcbb32a8b0cfd5f62daa2079cf8370b487cf440c664863e710ffeafc40cf374a58263139", + "0x16f6e49903922180e44d4bc45aeb65f093fe4fad10cf29583c3664cfbd76b9ca5b9a7ef2337a62cb2e45623cee7ced3"}, + {"0xc1fa03051d6150ed02ce658113c5b9de9232db80782740741c13e95afb61ddc78d32e0af5fa67e2df4203ea7c7f720", + "0x1a20dfca20c821fa263e1b04009e6e0f5a373e665afe7f603f0bb9703ce6864cc9ce09aa1e2d694a16082973591eed7"}, + {"0xed3c8528803a2e8ea1d51fbc40888c93aacdbabaf485d5a8a037472849450ed254f2bf0876516c81b466d03adc0b37", + "0xe0b3c359ae53e4901f777b107add779bd384d8da8a46c02f044cbeb099743b6888cc191d97bd035de9136783ac7866"}, + {"0x108e5399fb0e462641e346430020b47260782a557c8476b06aff3fa95b6251bfbd40dec8c213b3355c50a24b96d95d5", + "0x1aa7ad61ba7c96aaf8b72db59b48309bd72b50ec5781988ba9a55a43b4e4a595e36aceec3a51a1804a788848e9f96cb"}, + {"0xb16e02b02354b93cbf74b3551a94aabd0acfea5d6f20c56eb2f46433003d2dc4225912600eda79dc7e3adf0702e763", + "0xec85210b0e638ec662fc76335f470cbe21a165a66aad036058932f6d52e77f1b6e3269cce0432e1404b0810c053c2c"}, + {"0xc0b22a4dda3741b4fcd5b6c2abb9d2e8481ebd442e00d81865d70c8717d4c6c78a41e6f85c97b10fd010d8a966cbaa", + "0x1396ca7d90b82b12adcfcc5d81a850203097d56d9ef35381dc666cbaf594b4e033e6a525460e4ff6ba10bbf1afd94ce"}, + {"0x14c78f774a2896fa64a052004df6fb736bf806e662e9d7097f589b0df03fee5aee9609407005296ea99b879fa0ab8ac", + "0xcd6467d031974a892ff5ecff9f2f8d46a53e674500111351806a15432a6cf8744725b9c101161d59c792807b253a3e"}, + {"0x1526589e372650ab85ccf35382db0e7cf5d02f0de09e848caa73396338a01b9f6064695efe06eabef61098ea1c0c638", + "0x68acae9cd1355b5c9781656519838b804fbeeb960df4bff77dd2477ef674d7240676b62cb03a51326f8f47f14377e"}, + {"0x167a5b9940feddfc5ea3bae9c03a52e10fdb3b7055e547d27fa804baab5c74796d2f1cf56675c664229ecd622f32ed3", + "0x44f0cdf3744beae8718ae72373f6a01838b210bf23bbc13d3522d5595f45980057324c394fdd5f4a588716b2c0cf2e"}, + {"0x1511bd492587501195e9a7df7360c8e8fe72d53b57cec62eed296b202b156724087121691d7e7ac6d80656b40604602", + "0x51219c71bb96909a005e363c5ec60f36c77e407fcc05e801c3962f83566d18ae9ff4a658d0dd08e1d90de6c758bbe3"}, + {"0x48208860fc71ea0cb4a266e00c3ba02f8c272902831fc7d0a26d4734eb1fde8d496dec19ef8b076fde5c77b534f4ff", + "0x6707d246dda7a0a59b2b054307653dca9144172aa6281893bc9f681368f71325baca1eba0229dc19f9a7853088ca8c"}, + {"0x32a1895b110a91f8fb9e1bd01a312d28281131018a0ad9470c3c3ea1952f63ce90112b8d5ea7bc933d4f1cb426abe", + "0x6fced059c7cb1819994a13bcb3d805cb1170eb16e35561c90c1454c4af849c5eff11b66554ee507fec5c0ebc4eebf0"}, + {"0x182a668115cbca00c180b580798d261e58b4d2c140ccb68342ee5a859b51af3076e871060c103c2a0b4ca8a80a43a08", + "0x458656746821dc18aacaf7533ef33077889590c4eb36a545e120d40c812dad8bf3c8b3425a427a0f58e49460a4f7f0"}, + {"0x1371823e71e71d670cd8509978788f70e4aa0ad9e88dd3983c8b52a688c11865b8d1a183a82c866cebeaa40f4f87295", + "0x3fafdb6deb055c9eaa8a59bb2fafee94632d4c538c8837cca7743fec86a8f9ce24bdbf3e34595d1bb9e43571cf2370"}, + {"0xda0900c121f7a9a289faa9bd55ceaffe9d93a38a2b0890875289abe4a4491757eb96eebf7c2babb6169994d7eb414", + "0xfaa7103de621a04fad6afeb3e1334e1fe69a19029bf77e32833684a5e6c9f1a9fd6cbd6efdb6496b95fa4b20521f9"}, + {"0xdf001ab5b668caa34f373dea333476adfb1243e35453af80a6e66dabd825256f185763cb22112686723a50c47acaba", + "0xffdc67df2a8983f611da939f6b81abc4db37ecbbdb4409abf9e1eb6f763aaa51fce86f4ea92e4500079313a249d7a3"}, + {"0x2967da20443829494af8becbaac23650aab235202a7a20e64e52e0bfa17d045a066167931e3dbd41d55eb956d2ed10", + "0xc7f02fdee5f78a0a03e3abe964cb50d03313df2c8fe42b99d16f3af8a2a0bcc1a88449924ebe0acd21bd3ce63128fe"}, + {"0x13cac271335756e85815b2d299b18f25f34c16d33b8ff67e923b74f5c468196cc31ab24a3a7ee56ab9e4e10676fc0eb", + "0x18a1b7092e497c2b1ce9e73f447618dcb50b43e20f6115931833d0d1e79da6f3d728e4a1b651c0ff536cf2549919282"}, + {"0xd4ec1a90744458ece499140238ae77c1de76f242a8a05f1482eb221783eead306e1ee6c15da37f4363df82b6cbfd56", + "0x7eee2877ada79fb65b13e1af4d49a98ac24dbe7965a7dd9d4150274a31032ceb4a3a0aff0369ce7b15235d91cbbc25"}, + {"0x2b277ffeee377436109a9f871027362a333ae2d49c65c7452be93c50a2220673b21006879b1fa9b10c5c5f0d933f38", + "0x9b2ffda579da5430137b22b26fdaa13f52ff11c13f4f88fac0bfa0c30b5c1bb190d8728a60153ec7986dcd7dc5640b"}, + {"0x949aedd81f20923b0b0e5f5cbfc2c0cf7ba155ed488e756404f6adf9ad0c85e8bbe102a83693e805aff42b7f21617d", + "0x176910539df9c32d55b92b8f843c668db490d8905e108f18d1b136d45989a2d2ef4cfae817975c2729cc92032d905eb"}, + {"0xdd974b42d37d78da2e8761e99596fd113add085fc115b9ca57a94c218b278addb80c8430bab38b8d53738fbb33b75c", + "0x163fb82f31df72b309c3422ad404ce953f5fb5292fe68cb61b73100bc262a987e46299e183fc582cca8bc848dd7c621"}, + {"0x15d0fae7eabe20ca577fc60964b17e021e699c1f8ad28ecae4f3766dfcc924a5a89dfc48fa0945e9e650c45980affc3", + "0x16d1223b7d1b6311f2462306650b490d11b3772de34b66fd06810fd3dc56e90d15382767477c4952d25d0da2656d6e1"}, + {"0xb34a5e0ece8efa676afb297e8a81b8c5af019a878bee197bc4ecfabfbdaa46da1ed1a51cf3b0f1ed90691dcfd2d594", + "0x164c4047b6cc6e62f7c7a00c215157206c7b50adfc52435469ca2846701fd8857ca14c5ce17fde980afdf2b8ea58d2d"}, + {"0x167fdf7ff361330674041cc850f227daa736a1b450928a621273de03cb104998d76a529c84a9cd93a91ccde3cb4623d", + "0x18a6f2eb4840007bb2157cd6809ac05f522ae2e4047f77f4de06732445c7f03290de120acdbfe3d4590edf09ac3d0c"}, + {"0xf8649870cd6866641205263c10df90d9ba3c8b56d8ceb178c4897ead46bc3be88ef7e0e31952dd1396ac6f7905b8c7", + "0x9a05a5b1cba4d191bc5098efa547c070297e57748416d8386d72875a5cc5127d3a9109b88bb74bd7552b4eb3106175"}, + {"0x1378329c9fadb2e63f34a6f55ab5335ff1b5d913c2d7edbbba48295caa230f00150d65d25dd44880cb562ca912495c9", + "0xe5f0b2d55f8713e807c8fb1f96f13e0b5caa3de8607f04bd93a7260e3d8810a48860a9626c7b4a424bdaad21741308"}, + {"0x11386a65a011fb28d612fbc7d0f76b2dec1330512b504f541d09517a0cc00f0f49b6fc1fa52a8725965385dbae1f4b8", + "0x170632bca9a590287a0ffac955344cc8f15e59118f03adbf86e07bb82f5bb76cfb7fbf1e42a1eb384ff9c11f21b910c"}, + {"0xded86746533417ce10e14535b4811d2246eae38429763e4427ffa9dd12120df30c8c36497d089a06066626724c6cac", + "0x40ad9ca1fa683544a978c718fae74751b37a5dac2b57dcac813479f9ebb387e9ac1eafb90b12483b5282391738f286"}, + {"0xdfda607fa565d6becc5842deda97367bbf14db84a0cae4783dfb89d2ea2ccedefca2ec5883577294bba68a29815d6", + "0x137601d38808323444ab0018632b9e567be332256b624b8ce929756c42eab72fca278590b52071b38b711be22f5b0d5"}, + {"0x13dec721e4606cc9691488c3d003366a1462ba6a713277de0503f1131d1d61fab5c79cba5bb7332c6abc80435464be0", + "0x0"}, + }, + Den: [][]string{ + {"0x126e7ae82b984bc44d0e37b08e50643a99f06396f1ae9e20117c4bd86b9b1939fd92c3d95ebd307fce9080a95674e4f", + "0x18561a650deca0ad7df837e9ffaa27f0b8e85ff347362f1259d3b1e529e892327aa7c6ccf4a3ad6e365226b8d875fe1"}, + {"0x1a9963059b91cc5aab175a23fb536129d851da9e2f8c5bb7165e05937bdca1db1508e98843f1f62c047ce3d6ec8fc60", + "0x1fb73b0a8e121906f51d20eec7cb8491cb61bbb3b3ecaded3df7283d9128fc3635307f3c3ca133af720d9775729e91"}, + {"0x8b9ff20c9eba7b3dc948e79ce661704cf236ce6bd8361d146491031d3fc9e58b338a67ddc8548f4a36460fb5dceb40", + "0x3c27d81172a310833e5ab3bf81225b01c4068b13026ca1deeebad80a558665100bad779466ea0bc4ccf4c4ba3d9c7d"}, + {"0x1642ab99157e12e44ad3e54b1fa7a4ec2d80b545653fa336b5aa5deb0452f3d47824cdc51de8d83775d658426e24e3e", + "0x7d42c28d3d9fae9c3286c2dcb8826e91d7b36fc45468e8f64b8a029c91863cebd4add2412ee5f3bd090bcccda03ab6"}, + {"0xb233cdfc79172767df7df3731177932ce335fcff5e0b1579c01cf6d34d3747bebe1bfe3b111ef9176fbbba581e459e", + "0xbe45fabc97a7c23a215db4b2aae647fa5749ad332d9a66eccdcd7195a412def4d28ecb256f45d5879cb6b4e6e1d396"}, + {"0x4684f66af9512c51edcd89002de77e666b71ff7151c341319a44095d8113addf41f718b54842a7c29432ea9e2b8b88", + "0x88b603e95e15fff2d8bd1f77ceaf19ee06b7a9301faf29d983a8962bf7969a6b3ddbdfea1ee16f30cfb81cf7e21715"}, + {"0x354c69013ae211b621a899ca7a65f4bcbea4d39ea633002758cb777ba71f570995d52adceb2fc931d92a12398eb12c", + "0x175ca20c6e2e1b0b8305dc90cced8b1e4c3f4493d341e46e39b6e33741b604f1ae9f8b2be59f4a9a52e948c802a108c"}, + {"0x58a2ae5eeb2f349aa139ef3ddffd1df269c2cf99e23d6f64ed7ee9bd2cbfde0027449827b1e2b116da86ec051e0f07", + "0x47776d799a1f49c7bfa7feebaf8012282bb0dbc4b1ce41448474e41e53f64a098c71c79ecf21bece5867750a030982"}, + {"0x1a0a1098c733a0ba9c9ed018ecb794dfb3b84b048ad03850b46e6cfd1e1018fd25ecd9924e4cc4f61e490d92fe1ed89", + "0xdb1cc6b3b535c13494ba5c4ce330f401298118fb2c774b057daf91e1919b84ea0982828f8a07fa58cb3ea8f0201cfa"}, + {"0x1a19656718399a35e838587e3ca3aad4337c715ec6baf72f3c7e3fca08fce3651140c73a45031117e9e0ab0f7496b3c", + "0x11d225e689b1c5533a4da5615ccfd27032d2a33de261bc8c83e1d938637efe7b0612df05f42d2d858376b499c652d75"}, + {"0x1a97aec63b6f352e2a2494186b69f0276247a857d82f7879e7d6c01e4a38f6e9d97e347e87ce507a5b94f2b3773eac6", + "0x8256cc2663dc6938ae7605931d1a8f441ef85d2cef47445416cb593d2860d2eefcfd9a3c35d76d25d17109a764ebce"}, + {"0x9deeddd201ebe394bc84236d884b755378a169e31bb81e389ed375576782cb5fd30a4cbbcecabdacb808eab7c6d4fe", + "0x174a2760a9f8253d0539dec3d626f269841b51a989ce5205fcc09366eebf6535bab520fc56d623cd04fcde78d685a0b"}, + {"0x1e3c14cdeaa4ed3e266a36616cd141dcb32072e63e4b9c1b19eefc2d6b490397977352e865b5016f148f74d1234df6", + "0x5d1a7ce417ff6c955a2d06c4c840b541f386fe4a4370228afae2be534e2a5417fade1ead66031d64458270725699d6"}, + {"0xb44bcb83f10d65248dcf486aa2bdfbedc610b3f42aaea5a4581cacaad83d83a5bc9af704bbfd377d916268ed5be0ca", + "0x154a6f2aebf4c09b1e69a0a4d435958eab0b85a6f405246a1c6af4a4432e13ba0ae3e631b4cbb9958962a2bc05dadce"}, + {"0x43ec129619c24c903d1e8ced9e08af5e09deaaad2f85f5ff1a65a070055bda662d6b0ec13b2a12dce07dca1ca0d34e", + "0xc696b6c3b4b65ba99f95b0419f35d9f5a13e81f259173b4babc0bf290a0e2d9979511b5a6e1122aa7a572eb04c937b"}, + {"0x5f8d9df1cd3ea471f926003dae6e4cbe4eac8676d97693f76b082468922496ab47cf0a6fdbab2717328446ddecdc17", + "0x588223c67657eb350a8aba1f5ac04ccee4c02ab4a5c7d038c8a3eb8c8ebc0233950f6c7f12cdbb6fa6a423e97cd661"}, + {"0xe23936ef578d86d6e629e2146599905c9a3cfc4d158bb35f4513ade1031830de7ca355bfb3ec74c487f7e91dbaeb22", + "0x1168faccfe32c916ceece34bd697bfa7aad4048bf1ef00409f0c7ad20564f46eac4e7710083011e85e8543b1b8b3c3e"}, + {"0xce947ebe5063aafb2a3e9796bf3677237ecd980026889351d1120fa73b24a1a04e971deab8ad4c7f189e9559b0d1b1", + "0x156b554c56db14b68a4ed5367a442fac6d95d2714fc59e9eaa235dba01a804277302625ce66f99e4eead7b7c7137a90"}, + {"0xeb0854aaaa2035ec173a3419093ef828c51df43b492dfad54fa62fcdcf40621c21d040f678a3eab5831e12e4a0d02f", + "0x380b52ae6bdef0a4cfeab3cbef0efd4017286319f2e1dd8022fd896cb0cb8be986c4abb1ec2bd6aa90c45b1a61b6aa"}, + {"0x19cee627a52ee5d83bfba584b81e8da3e9fee36a4785cc5e277a0635ad178c03863d708258214e80851cec3bab077b0", + "0x19a62cec87d6fa62a59d35af20772f84611a11d62e573e008cf6cc4e6e473a93a89b0b2b4579827b835109ffae07696"}, + {"0x193224b2c9149c504131017f21f51adb859b41abcf51ad61eca54273f7962d47bbe4c33a96e0938b31d4d475e20c472", + "0x17c9844cbfaebc9866e792216a887a4efe3c85a55891e1f8e0f0c5bcd1276e607087e9a67b9ca05b30577a70e0b9cd3"}, + {"0x1a381bff3a99144474ed68d432a55cc7a87a77ec8ef9ec7dc8207bebe95d55bda2ec40d34992be5e68691717ad25e87", + "0x1998a69751dae99d28fafd96b81cc341482051957408078e8ea74617fba8242075a8f8b079f1e18a274a9defcf12cf9"}, + {"0x1436817e660a5107b3d259cb3f2af5d373b951ad6a54ad6831ff9d7053cd857ae5abcdf0e44bb1a45dc4dc43be82a24", + "0x7d2fe1f55c31673b19f9fc000ffa74819d7001a3f1bfcd87bad06d6642b6ebd2d69836d88e9e43fa6af8225a380ed6"}, + {"0x321b8a5f187405be1d90830e71a287eadc2722bc45bb9f5e84a921331835127361f4544d86b4ace8ceed8886063f02", + "0x58cd6cd7c128e53ec5f4b55e8cb0356e36b4f4673890bd57600018e658100e9ebe25311b6c0a9b21b95a6414a88ad1"}, + {"0xa88afc381c5826291bd27ee2a6d88bbf10068154b09f1df0b3cbe9478e2f2f835133d5486b0797d9ade242e0d442c7", + "0xf76768c2ed3f4e85913f870de4ef972299114025ab5bd97a70dff551d3fdb6e780876e8d5979631e170590f104b3c6"}, + {"0x6bca067bf3c3fda8fe8060531d6f5550fef83c2769c7686682abf9585ca3fc04d64a75061c9965a8782864126167f9", + "0xa0e802a11d90c37cd105a8c597cb844efb81706dedf9a6a19254dc7db8b0bec5127ab383370ddf3ea8426be5d2d9d"}, + {"0x46d4e78de408979012bcc8d12b78d6d85d8beca1b7700c410fa6a3b78de2b181a3b2d464d3d1745f5a4f722bcf667c", + "0xdcb51648143fc79a24093a797cda524c95512a51d521ec38321e624b1cbcdb9dd278c71eb0fa345eb67639e9563dd8"}, + {"0x1620bcb2404787ee39cae59ba2c85a2062aed25694677b198fed619d6558b859da3aaad5d38e773ca645cd710379803", + "0x10620b57ed7f896194775ed566c2e01276e4f7bcdf233a23ad1d3e9b77c3fa0cdf84c564c1021f5e584458ab26bd8b8"}, + {"0x6dabe74a1d15321e50aabfd662991b784c84a9b72e3340eee8efe520e68624376814038f2d1d683df0cc4f81c37a3", + "0x130be04e20fed0aabac1be1a13614e262414e7492e8701816e89b9982a435e2cf80b11474358c9bf758393f8fe05022"}, + {"0x83889427d535bd6411a28c2a0ac1d40396ee0e686f0052f0bf59abb62bd3004f1ff3a76bf93b70926638b5c05f0a3c", + "0x131b916656d906aeda904a98d7664ed693a9a793a051a824c4ed8c815835eed2bcf1d686414c859af676f850e3dfd71"}, + {"0x160c9ea53e9e85745773c4faccea8a4bc12d558b01068c2f3d88ca4d43b6f5e338a0ab7230fb044757ec2666f769dbb", + "0xb40e44b0581a642829ebdc74a3579c83018737cb432db5f3d692411082f2139753f6122e53566737d4ef53ac06ad1"}, + {"0x186657fc77b2f47a24d4ce9ff9978c8b856ebb1d23e75468ac95d73168cdd6f7ae9ed767ad52bc9a3ea835a37c34aa3", + "0xa216aa737f6a614825bc46fbbcd767235927731a2c14c71ac6e2a38da8479785028a30559d92f544c2cf5d24b542fd"}, + {"0x11e53de7dcd97d4850d8d3b3d948db5e1a33adf4d3b81342b155f926729619cf1094cb81ca5119e69a84307aa35cc4f", + "0x15ebff8d6d9c62eada64518cd85683baffe02073d8191ce5006a93c64dd1aec73e6f5c2178face4ded883af8b0738ee"}, + }, + }, + }, + }, +} + +var tBLS12_77 = TwistedEdwardsCurve{ + Name: BLS12_377.Name, + Package: "twistededwards", + EnumID: BLS12_377.EnumID, + A: "-1", + D: "3021", + Cofactor: "4", + Order: "2111115437357092606062206234695386632838870926408408195193685246394721360383", + BaseX: "717051916204163000937139483451426116831771857428389560441264442629694842243", + BaseY: "882565546457454111605105352482086902132191855952243170543452705048019814192", } func init() { addCurve(&BLS12_377) - + addTwistedEdwardCurve(&tBLS12_77) } diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-378.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-378.go new file mode 100644 index 00000000000..b30d9b05943 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-378.go @@ -0,0 +1,74 @@ +package config + +var BLS12_378 = Curve{ + Name: "bls12-378", + CurvePackage: "bls12378", + EnumID: "BLS12_378", + FrModulus: "14883435066912132899950318861128167269793560281114003360875131245101026639873", + FpModulus: "605248206075306171733248481581800960739847691770924913753520744034740935903401304776283802348837311170974282940417", + G1: Point{ + CoordType: "fp.Element", + CoordExtDegree: 1, + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E2", + CoordExtDegree: 2, + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + Projective: true, + }, + // 2-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0x3eeb0416684d18f2c41f0ac56b4172c97877b1f2170ca6f42387dd67a2cc5c175e179b1a06ffff79e0723fffffffff2"}, + B: []string{"0x16"}, + Z: []int{11}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x2f304310ce39d2c3011a6d50eb4ece730cab541269dbc53c7594241b1c244eff01c0ce03cbe00000000000000000000"}, + {"0x9d9ea03fd9a908c76d1012fb4743eb0c720b5849c7b761ff1e3f31fc34200004ca4510000000001"}, + {"0x2f304310ce39d2c3ed885db0b1cc5b9e3043708b54c1a5cf20a52889c7b761fdaf1f98fe1a1000072f6798000000001"}, + }, + Den: [][]string{ + {"0x2767a80ff66a4231db4404bed1d0fac31c82d61271edd87fc78fcc7f0d0800013291440000000004"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x2f304310ce39d2c3ed885db0b1cc5b9e3043708b54c1a5cf20a52889c7b761fdaf1f98fe1a1000072f6797fffffffff"}, + {"0x7dd6082cd09a322f6a993378ddbf030e107849ad95ef7bbdbc611d64e38ea7c4e9cea46c7d00013291440000000002"}, + {"0x1f75820b34268c838ac8d9803d05ca3f43c5122b2366f9c76b7f1f7530b7fefd221e864e5f90000bf9aca8000000002"}, + {"0x370da3939b4375e4951f17f8cf6e6ae3384eadf7e2e1ec1c50c0af4b69009cfd4c4f87d31e68000861f8dc000000001"}, + }, + Den: [][]string{ + {"0x3eeb0416684d19053cb5d240ed107a284059eb647102326980dc360d0a49d7fce97f76a822c00009948a1fffffffff9"}, + {"0xec6df05fc67d8d2b23981c78eae5e092ab11046eab9312fead5ecafa4e3000072f6798000000000c"}, + {"0x7636f82fe33ec69591cc0e3c7572f0495588823755c9897f56af657d2718000397b3cc000000000c"}, + }, + }, + }, + }, +} + +var tBLS12_78 = TwistedEdwardsCurve{ + Name: BLS12_378.Name, + Package: "twistededwards", + EnumID: BLS12_378.EnumID, + A: "16249", + D: "826857503717340716663906603396009292766308904506333520048618402505612607353", + Cofactor: "8", + Order: "1860429383364016612493789857641020908721690454530426945748883177201355593303", + BaseX: "6772953896463446981848394912418300623023000177913479948380771331313783560843", + BaseY: "9922290044608088599966879240752111513195706854076002240583420830067351093249", +} + +func init() { + addCurve(&BLS12_378) + addTwistedEdwardCurve(&tBLS12_78) +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-381.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-381.go index 986b28e472f..15d5c3f4b8c 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-381.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls12-381.go @@ -8,6 +8,7 @@ var BLS12_381 = Curve{ FpModulus: "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", G1: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g1", GLV: true, CofactorCleaning: true, @@ -15,15 +16,153 @@ var BLS12_381 = Curve{ }, G2: Point{ CoordType: "fptower.E2", + CoordExtDegree: 2, + CoordExtRoot: -1, PointName: "g2", GLV: true, CofactorCleaning: true, CRange: defaultCRange(), Projective: true, }, + // 11-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d"}, + B: []string{"0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0"}, + Z: []int{11}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7"}, + {"0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb"}, + {"0xd54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0"}, + {"0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861"}, + {"0xe99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9"}, + {"0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983"}, + {"0xd6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84"}, + {"0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e"}, + {"0x80d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317"}, + {"0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e"}, + {"0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b"}, + {"0x6e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229"}, + }, + Den: [][]string{ + {"0x8ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c"}, + {"0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff"}, + {"0xb2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19"}, + {"0x3425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8"}, + {"0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e"}, + {"0xe7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5"}, + {"0x772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a"}, + {"0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e"}, + {"0xa10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641"}, + {"0x95fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x90d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33"}, + {"0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696"}, + {"0xcc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6"}, + {"0x1f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb"}, + {"0x8cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb"}, + {"0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0"}, + {"0x4ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2"}, + {"0x987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29"}, + {"0x9fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587"}, + {"0xe1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30"}, + {"0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132"}, + {"0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e"}, + {"0xb182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8"}, + {"0x245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133"}, + {"0x5c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b"}, + {"0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604"}, + }, + Den: [][]string{ + {"0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1"}, + {"0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d"}, + {"0x58df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2"}, + {"0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416"}, + {"0xbe0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d"}, + {"0x8d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac"}, + {"0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c"}, + {"0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9"}, + {"0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a"}, + {"0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55"}, + {"0x4d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8"}, + {"0xaccbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092"}, + {"0xad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc"}, + {"0x2660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7"}, + {"0xe0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f"}, + }, + }, + }, + }, + + // 3-isogeny + HashE2: &HashSuiteSswu{ + A: []string{"0", "240"}, // A = 240 * I + B: []string{"1012", "1012"}, // B = 1012 * (I+1) + Z: []int{-2, -1}, // Z = -(2+I) + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6", "0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6"}, + {"0x0", "0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a"}, + {"0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e", "0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d"}, + {"0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1", "0x0"}, + }, + Den: [][]string{ + {"0x0", "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63"}, + {"0xc", "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706", "0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706"}, + {"0x0", "0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be"}, + {"0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c", "0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f"}, + {"0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10", "0x0"}, + }, + Den: [][]string{ + {"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb", "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb"}, + {"0x0", "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3"}, + {"0x12", "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99"}, + }, + }, + }, + }, +} + +var tBLS12_381 = TwistedEdwardsCurve{ + Name: BLS12_381.Name, + Package: "twistededwards", + EnumID: BLS12_381.EnumID, + A: "-1", + D: "19257038036680949359750312669786877991949435402254120286184196891950884077233", + Cofactor: "8", + Order: "6554484396890773809930967563523245729705921265872317281365359162392183254199", + BaseX: "23426137002068529236790192115758361610982344002369094106619281483467893291614", + BaseY: "39325435222430376843701388596190331198052476467368316772266670064146548432123", +} + +var bandersnatch = TwistedEdwardsCurve{ + Name: BLS12_381.Name, + Package: "bandersnatch", + EnumID: BLS12_381.EnumID, + A: "-5", + D: "45022363124591815672509500913686876175488063829319466900776701791074614335719", + Cofactor: "4", + Order: "13108968793781547619861935127046491459309155893440570251786403306729687672801", + BaseX: "18886178867200960497001835917649091219057080094937609519140440539760939937304", + BaseY: "19188667384257783945677642223292697773471335439753913231509108946878080696678", + HasEndomorphism: true, + Endo0: "37446463827641770816307242315180085052603635617490163568005256780843403514036", + Endo1: "49199877423542878313146170939139662862850515542392585932876811575731455068989", + Lambda: "8913659658109529928382530854484400854125314752504019737736543920008458395397", } func init() { addCurve(&BLS12_381) - + addTwistedEdwardCurve(&tBLS12_381) + addTwistedEdwardCurve(&bandersnatch) } diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-315.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-315.go index 0c07686195f..835e01ee98c 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-315.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-315.go @@ -8,6 +8,7 @@ var BLS24_315 = Curve{ FpModulus: "39705142709513438335025689890408969744933502416914749335064285505637884093126342347073617133569", G1: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g1", GLV: true, CofactorCleaning: true, @@ -15,15 +16,59 @@ var BLS24_315 = Curve{ }, G2: Point{ CoordType: "fptower.E4", + CoordExtDegree: 4, PointName: "g2", GLV: true, CofactorCleaning: true, CRange: defaultCRange(), Projective: true, }, + // 2-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0x4c23a0197b9ca68541a4cef14af4cfe81cc324cac5626d9ff4ee66df9ea2678877910f40300001f"}, + B: []string{"0x16"}, + Z: []int{13}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x2611d014c792a8ffd30982483b3ee757787d35c9e880e096a850c8e24edf5c71f880eff103c0002"}, + {"0x2611d01644a40e35d2dad31956fafeee9f1a0831db5b7b49ac10c81d6ff9afd483bf88000000000"}, + {"0x391ab82082520bc9ef97728ef1d4703e7115c13f9db942831972c63be0e6bc1d3ee023f70240001"}, + }, + Den: [][]string{ + {"0x261b56ebccc821ae82c6025bea42e1d731e2a911e6c66652b682a1f0411fdc017f9ffffe"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x391ab82082520bc9ef97728ef1d4703e7115c13f9db942831972c63be0e6bc1d3ee023f7023ffff"}, + {"0x391ab822bdec239aef516bc89b6e93a12b00fcdb8a012a8f9f12c514928e39310fbe080d7c9fffd"}, + {"0x391ab82166f61550bc483ca602787e65eea70c4ac90938ee82192c2c27f687bec59f4c000000000"}, + {"0x429f2c25ed5fb86b978605a6c4cd2d9e2e996174e2ad78439db091f0866286221eb029f582a0001"}, + }, + Den: [][]string{ + {"0x4c23a02b586d650d3f7498be97c5eafdec1d01aa27a1ae0421ee5da52bde5026fe802ff402ffff9"}, + {"0xe4a40986ccb0ca1710a40e277d914b0b2b4ff66b68a665f0470fcba186bf2808fdbfffe8"}, + {"0x725204c36658650b88520713bec8a58595a7fb35b45332f82387e5d0c35f94047edffffa"}, + }, + }, + }, + }, +} + +var tBLS24_315 = TwistedEdwardsCurve{ + Name: BLS24_315.Name, + Package: "twistededwards", + EnumID: BLS24_315.EnumID, + A: "-1", + D: "8771873785799030510227956919069912715983412030268481769609515223557738569779", + Cofactor: "8", + Order: "1437753473921907580703509300571927811987591765799164617677716990775193563777", + BaseX: "750878639751052675245442739791837325424717022593512121860796337974109802674", + BaseY: "1210739767513185331118744674165833946943116652645479549122735386298364723201", } func init() { addCurve(&BLS24_315) - + addTwistedEdwardCurve(&tBLS24_315) } diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-317.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-317.go new file mode 100644 index 00000000000..2c5a3f89675 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bls24-317.go @@ -0,0 +1,86 @@ +package config + +var BLS24_317 = Curve{ + Name: "bls24-317", + CurvePackage: "bls24317", + EnumID: "BLS24_317", + FrModulus: "30869589236456844204538189757527902584594726589286811523515204428962673459201", + FpModulus: "136393071104295911515099765908274057061945112121419593977210139303905973197232025618026156731051", + G1: Point{ + CoordType: "fp.Element", + CoordExtDegree: 1, + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E4", + CoordExtDegree: 4, + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + Projective: true, + }, + // 5-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0x8e4edadd82ff003e6762cff9b559b8cd0f3f6c9311276a6d560dcce30e697a982e1866e3e7c28d5"}, + B: []string{"0x2064f87ea0196ecbb9b075804c613d4776224e78064823a8568e30f5ad5af3bb70ee17723af3a0d"}, + Z: []int{8}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x236b5fd9cca05871bd84a4837633e369779c83cdd8e57f5e6c225b947983cf102a89412ca193804"}, + {"0xbd5fdd72856b15e73452512781cb8a44afc43fd20722b37bf41b260fcb6b2a53697eaaf34dd4055"}, + {"0xe48ccd9c11799e37b9f9713ad4c23c792bfe9cce20bb64b953983bb7789d7a5d28b1cfdd29c6212"}, + {"0x3c02ee7a69adc553341746545c583c06a0d844f638330a35305f5e8e312457c0ab57bc2702dc270"}, + {"0xc836be99bb812fca77c672366482945f54dd793103efb9504eb992da7132416060b75c14fb7999e"}, + {"0xfb165e39e1f3c02308a056717044d039ad1a5aa191127f2160837936541ff83badd4b3430f63d71"}, + }, + Den: [][]string{ + {"0xac526aaa4ccfab9e20d1af55e1b46e59df4ccdf5efa58766d0c18ac6326551818ee9e90fa19a875"}, + {"0xd8ed9eb76dc3ca65e3c54629ff1dbc57619627e2efb082c3f4601ec65d293de69e57eb95404a6b1"}, + {"0x6fc49fca38657cde5fab7a027bf50b888cb23b6952698615ff744257a41fa35df7f708c34184a19"}, + {"0x23e8941f0cfac565a7a6787558193984724c940bb5db04b86f4a98572244fc21a180f77d539d5bd"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0xff4f99c01dfcb3892a91fa883b348828de9460cb96389fb35ffb06434cdeef1ce46b03c5dd5d0f7"}, + {"0x81224ed3f6692419ae30d702d3eda4710053bdbae2d49fe1f4ae22ca850ba727e1ccf7e5701c164"}, + {"0x45054affadf894503d5833cfd9dbad5eb905a527a12b5e7dcabd0052793f9b49e64e957dd42da4"}, + {"0x18eeec003ff866c9fb04c7371fc3383d385a2be91d8a0433f6974c71a0ce405f122c83719f1393e"}, + {"0x31dd068a643f47a6596e317e958886ea2ac504968e1c5cf09c8d5776c6643ef4de74fbdd8c4a619"}, + {"0x2c8e3ae176f645fc860fce8de1b13b50c4000167d09963c6e1a9c672f88f4f8d0503c022726fc95"}, + {"0x9f05a21397a2e89eb8a9d058e93ca60265193966535883b745a89991576994ae547e2d441247c3f"}, + }, + Den: [][]string{ + {"0xd3e018c50c3942dd4d09a4ab202a25696610ba38204d026ecdaf526c2f6f7087e577ad578cd63a4"}, + {"0x8287e2ff37ee6fdebecdbb7847a885def88d0241d5cff2567cb4bc388b67da5687eb6031701f843"}, + {"0x59d82ad3a832a32188e27cac33b5e6c5598cb76c8ac13ef00b5d65852db61f05669c372e5dcc771"}, + {"0x56b84eb18c4f8eadcddfdda011cc2f7b5c06990035936f127ba77996f19017f4ff02c13009b3e70"}, + {"0x7d08817b694fb1681686e845fda634911d8d84dc73472bbe89ad038a351d9729f4e2626dc0ec353"}, + {"0xb8a32f420e7c71800ff7e1b5c3f4580f6045ed45b702294b5e89b3a4548d7626dccae5eeeac55f1"}, + }, + }, + }, + }, +} + +var tBLS24_317 = TwistedEdwardsCurve{ + Name: BLS24_317.Name, + Package: "twistededwards", + EnumID: BLS24_317.EnumID, + A: "-1", + D: "20748505950524021841644589704740731932416084248011369709738936344973878925081", + Cofactor: "8", + Order: "3858698654557105525567273719690987823069521430163883173133245580997415449969", + BaseX: "4348505656527095883506785370890963704100065639426869666063106978260788240233", + BaseY: "1929349327278552762783636859845493911537170411830425720219700276810167091201", +} + +func init() { + addCurve(&BLS24_317) + addTwistedEdwardCurve(&tBLS24_317) +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bn254.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bn254.go index 2b43f717a60..c3c90748c37 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bn254.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bn254.go @@ -8,6 +8,7 @@ var BN254 = Curve{ FpModulus: "21888242871839275222246405745257275088696311157297823662689037894645226208583", G1: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g1", GLV: true, CofactorCleaning: false, @@ -15,14 +16,57 @@ var BN254 = Curve{ }, G2: Point{ CoordType: "fptower.E2", + CoordExtDegree: 2, PointName: "g2", GLV: true, CofactorCleaning: true, CRange: defaultCRange(), Projective: true, }, + HashE1: &HashSuiteSvdw{ + z: []string{"1"}, + c1: []string{"4"}, + c2: []string{"10944121435919637611123202872628637544348155578648911831344518947322613104291"}, + c3: []string{"8815841940592487685674414971303048083897117035520822607866"}, + c4: []string{"7296080957279758407415468581752425029565437052432607887563012631548408736189"}, + }, + HashE2: &HashSuiteSvdw{ + z: []string{ + "1", + "0", + }, + c1: []string{ + "19485874751759354771024239261021720505790618469301721065564631296452457478374", + "266929791119991161246907387137283842545076965332900288569378510910307636690", + }, + c2: []string{ + "10944121435919637611123202872628637544348155578648911831344518947322613104291", + "0", + }, + c3: []string{ + "18992192239972082890849143911285057164064277369389217330423471574879236301292", + "21819008332247140148575583693947636719449476128975323941588917397607662637108", + }, + c4: []string{ + "10499238450719652342378357227399831140106360636427411350395554762472100376473", + "6940174569119770192419592065569379906172001098655407502803841283667998553941", + }, + }, +} + +var tBN254 = TwistedEdwardsCurve{ + Name: BN254.Name, + Package: "twistededwards", + EnumID: BN254.EnumID, + A: "-1", + D: "12181644023421730124874158521699555681764249180949974110617291017600649128846", + Cofactor: "8", + Order: "2736030358979909402780800718157159386076813972158567259200215660948447373041", + BaseX: "9671717474070082183213120605117400219616337014328744928644933853176787189663", + BaseY: "16950150798460657717958625567821834550301663161624707787222815936182638968203", } func init() { addCurve(&BN254) + addTwistedEdwardCurve(&tBN254) } diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-633.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-633.go index 9ff8f9db83e..a0584e29ea8 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-633.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-633.go @@ -8,6 +8,7 @@ var BW6_633 = Curve{ FpModulus: "20494478644167774678813387386538961497669590920908778075528754551012016751717791778743535050360001387419576570244406805463255765034468441182772056330021723098661967429339971741066259394985997", G1: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g1", GLV: true, CofactorCleaning: true, @@ -16,13 +17,111 @@ var BW6_633 = Curve{ }, G2: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g2", GLV: true, CofactorCleaning: true, CRange: []int{4, 5, 8, 16}, }, + // 7-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0xb5b90ddda6922f2689cf6d2cd62fc7c093d1edbb9b9cb78ba3a6fbeb5740830110ea006288b01bc5c3ff21599bc76c3cc068855d91995e0a03f25ad67e9b0cb86f833df84de9affcac130e2de80208"}, + B: []string{"0xbb475f2945d16aae79792dd2f17748101c2558a952d4221e5a52bee6083040e779fc8d5e9c51ac35df601e0273b10c72f2b0d48da6bbc3859a3b185a7ee3060030e001265b3803227cb9d879f408d9"}, + Z: []int{11}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x172ae0280920320d5154453cfc38fb78e8f3cc1f3e35c38bfe870403008707ab1c9d324595b739426a3f8e03cc03f4d2e6a3b21c833c83d2c147adc9dd927523d2b556276090b4e6217d4125c656bc"}, + {"0x3ac72438aeb5851d31e592b661151b037c9a2aab88cd7a2da79158e39dddee35c360788859c6aa878660fba8caaa9f8ff6480a0abcb9f9122c929e9b673eb8cb8ea164ca1e9eddd03b4155f0ca87aa"}, + {"0x6f2cca97746292add854c01e5d06bfd8282d74cbcd0e7169e2e310ca27302cee61398208840e20a9d6ffe43db9c520799710059df25e8ce05c304f59d65d4e596cd1c587a7f6f1096e53656f93f1cc"}, + {"0xab5eb0567468008b2665f73dd0c7711c3166659434e0df8f5902de8acae5cccd4707d236e5af68f88a02aacae38e2a2bd3b5bf4442e127a36d13a47260eee3fc97ba5d9d5e15d105e256c0d86e9b96"}, + {"0xd6c992e6deb66a0d2cc1008c227fcbfdedcd136cca4dd9708cf0217e554124030fb2032803e9620d8af19f3aed51abf6d98ab2be038495edf761550d84fd1fc92f803661d045879877b8eeb2d62c3f"}, + {"0x5964f96bcd18903bd4385390d129f87d141bfa129dd9b10c1657e88b13aa4830591458fe69f1c5422f8a9c04dd9ae4dfc55d44546d129f4b4bc708af118b9ce685bd0b9480e21af262b9fdde470769"}, + {"0xdea100c7e48b278c46938a6636d0988eabab86cc555a2988cae5b7c5ec0c8e9090740796a622b4ba807360da51be9823c7844464113d8cf0d134409f68758d4500cdf13cf6bc705cbb3b26a6b91ffd"}, + {"0xcc44dbc9cd7135b427007ff6d3fe49ce12b5c3cdec0a6af272524c19b15decb7c66941fc70b0e1cea225709a41d8da2dac0afeaf69770aaa930ca8be861e392fb2f3f5b8662e2a3757495ea31eb1ab"}, + }, + Den: [][]string{ + {"0xdcedc9bc56dade3f84967eaab07772e6382d825c853b5f21b2aa334ece09ca419a918ad532943018c0af9c373d006d5a5db3dae9cacbac8e1f7ca091dbb63f6e6f6beaee1370beaea58439a6b07a79"}, + {"0x195b81736d1c96d7a634ccd1a30ce5322c4d511b000e0c45cbe40e4fc193787b0b60086e3e4d2eeaf56537fcc1d7dde1305f6f1f43da15fa5a860515b5ebd80a71de65dfa88d88b4dde8a70ebbe4d0"}, + {"0x7306846c2c81b999dc05637178c43d7bcaa8f060fa6118084a2a801ba72736fbd0a2af9da70982f1e36c1c2485775de607d049a5faf6494d4d3eedd3ff5a760faf17ed0596c1e1a8aee8112ae305ff"}, + {"0xf148e1a26098d0488ff6183b6455f5e6605c502a1eb3c11e32096d10f777563a99faa0dba8835bfea9529f125f36903c681c7d9dd0bc814a1786cf0813388a804eca85fbaa5bdd78f7d746269d6bba"}, + {"0xde8e351bd12bb3d5af8b63954d0f78bfb4bc60813ad171eb74cf3eba9f691dfb1dfe147ffef06b9aca6a77d845184de3d4ea5948fe12fccec2371477802f2f6e865c39af78f97e392a54f81cb069fb"}, + {"0x10795e5f91d91e69bcdf124c64c0f1e2507ffc99bacb24dbe7d3cb6a07de6bfab41b8f939edbacfafd0ce0b72a847fa1169d64cae412d7eac428a1e2a570a85c42e5ab2bd355b6a2460289e03f1d8c"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0xc0e9192eb96da62a98ed351e9c479d437e885f7b173bc0e8b5e117be8f9bc0b8784293b4edd36184584c570f1bbacfa6390dfdab92c1102aff64793eba4e0ca54166b6ea37f041d97e17d6b8793f59"}, + {"0x2ad94cfbe3e7c1f6c73f4b7986081a8747e453a324f5fef697f4bcd681b93764606aea1c234fcc16f02941c568e7e0fc9c970db8891079fecbb13a701870973155097603fa2a95f3a9814d630920ce"}, + {"0x4fe83943570d36473c925cb80651566f48ed1a12583a0ba466a4002cd5d81324bedc2af4685ce69e8ac8c982eff0e88e8983860fc7c365efd617110a18f8d2cd2c5f5a764656d1f0acd219dfa36482"}, + {"0xb2169bd7a853b597c830c30e580e9a4d2e3c25dd81b72667ca4370b2a978cdeb7bc9812693ef630bc510a4151170ad8c0618c4a038608977391fd3d83479456ea6802236a0b3de82ce1017e1a8ca6d"}, + {"0x7f25b01ef9844f28aa0a93cffc07a16e1cc68544c7f6772babb491e4a268f152a38b8b45123c9b054de66169553ba6059e8af4dc33ee26093d08489f85450d8c5be80f1ba5aeb2c0d0afd9f92a9122"}, + {"0x566545c6ba909462ad89503f026cd53fa3d34c013226c353b14aa982fb2fb682901be8b4a6341ee81a65270009af992892249cef724bf97898b1c3fc17377d4432a23894970c6dcb3583b60c84fa24"}, + {"0x63e2ccd9a60b841370ac46210ce9788ae1562f251ffddbf6c1999647217f1fb641c6b28725006db4784cda2bb6149c5f7e8a0e1262cf65258d29f63eedcf4651d9cc6f36cf1754ac816f22fc61b9c7"}, + {"0x3f2fa1f528148f6695c61636ddc28b114cbe73a59ff01987fa09ce591615c9c3588f43eee553df2b678321a7348d1d9609316cb0a7a99d816beb08586b2c6f140dbef23f030253c0e4c06208d60788"}, + {"0xf607a90cc520cf3642e858f10134f611165201f1a19d8aa556830a8d119c70f050ade9579d2af2437e4daed7e8413b7eaa57066a4f1637a9eb355979a9069b53019d4f6a3b12bd11e65f30fb97928"}, + {"0xcdfc4b597b44fc122ba1d93dbe1c643d84e251481f80d31b34e546493c89bd3a651ed920fb518fce37f21fcd0850fe6e97f9e08e774242b04f71dff19a9b401ee3c8d55d71cb9849041ef6054c20e"}, + }, + Den: [][]string{ + {"0xecfc2a8f34b76242cf9989e6693e365112eac88902ea95115bccd5bb49a664d72b2eec54104241f9c5f1a68018d8eb3db2d854d09b081df9a369bd4312614d50899c909fbb2d2b52a7635c4d17f8b7"}, + {"0x742dda08c1fcb9436c2bc5f52af4d8189585537efd4b1a7f91fa77b5f737b8c6fabc388a01078294e7dd2198b8a32fa89354400dcec753d887b198f206ae05288915451a752ef75b75d8c360ea36bb"}, + {"0xc1d1190593e7a0686859a609ff1b46e11c0327a20872f72279a21b183a44281d0cee21d747715e9dc19f973b098c1dd3599593b70f85733addf045ea08642a6f840f99002986bec1f94bee017cd4f1"}, + {"0x97e05de3ca9556f56ecf4d1ea23a7e2d2712c0ae94ae9e446d965d7004b483b7422f99fed04fdddbc0c2d7fcc1145f04ad2f384637ed52da52a2fda64c67d29b756381ab78f85d74ec8086cfcb9179"}, + {"0x75ad4fd71ac6a390fe643f2d7e58ab8e47679afea937b2fa282221167c5e439b8d0b71d9d9c415aced0755ce72f558c6b966b4103521c4d576e232006e02ce0aea7d969d59bb6aa7fd0464bb753ee9"}, + {"0xaf031142ce65bb40b7b4a865ddf8b662e90c8f6496d6e4efd790353e79905de96971b0e90ecbe0ca95cb602145603cf7e33d79207c766500002418e725368fd15fef6ad5fd2d70dde8e192180d408b"}, + {"0x906c22013e788817b69f3c5705a7dbb9efeedabf5d8f091b518cde2891e351aa73cff16f909a2aeb160dc3e26f0ea78b07d327cc073494f8fa334f7b15c42f6454ec151ac079a3a0802d1f9eabbbc1"}, + {"0x9435c646c7573441604b5c0e0a53569e9440440e3e8df291c6ad158f942080d9a60829e933883e3bdbc574fc459c167608aa11e7b0ad4ec1c35e29c0cc81bf2b7481e35d0821b52e5ee02dde63ecf2"}, + {"0x18b60d8f5ac5ad9e9b4e9b7297216ad378bffae69830b749dbbdb11f0bcda1f80e29575d6e4983787b935112bfc6bf71a1ec1730561c43e0263cf2d3f828fc8a645880c1bd0091f36903ced05eac52"}, + }, + }, + }, + }, + // 2-isogeny + HashE2: &HashSuiteSswu{ + A: []string{"0x37406b7fa0e08ee1ffbb1ff2ff0ac49e29ba75a3caa8356b90991ae70b94d33807a85e57856205541ab2cb490d6980835d627d3d10b29e4d73a43caf3b5042cf1f7ab420fd005e2d747ffe14"}, + B: []string{"0xb0"}, + Z: []int{2}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x75c14b832491ee6015aa114d85d2ae69f27a247446da31831298835185ff04f44ee6dccb2179be43cf8cd0695188add97e49c08a2a617963eb40e8291283e4750d0e7862161f19fc5d41132e666653"}, + {"0x3ae0a5bf44ef27340179bf3c1b1d57bfae1f8ba310fd8743c24a07d811f3b8d9abeaa1653f0e462703b0da08e15133e1856a302131162f7bee2f30da626a15980dd9c8e5109d60f3a3f1f25d03333f"}, + {"0xdcca6d90b6878afd13917b416160083ebda295861b5e157ac318f4234ce3a3a0fdfd10bc26fb6c8aa3f786e2f81d371e8ae63cb24e3b05e1c85adc0a2b519bede8f4de4cf5f96da176d12fb414000a"}, + }, + Den: [][]string{ + {"0xeb8296fd13bc9cd005e6fcf06c755efeb87e2e8c43f61d0f09281f6047cee366afaa8594fc39189c0ec368238544cf8615a8c084c458bdefb8bcc36989a8566037672394427583ce8fc7c9740cccfc"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x126633cc0f35f63fc1a174f01d72ab5a8fcd8c75d79d2c74e59769ad9bbda2f8152a6c0fadea490b8da9f5e83f57c497e0e8850edbda407d7b5ce7ab839c2253d369bd31147f73cd74916ea456fffff"}, + {"0x93319e5991a24209f0f9cb40f4315c749d13cfe9859aaf2dd7b49ffacac9badf36b8f97c7a467d6bc10f04bea464bb9d5a14180b32825c49c49373ada8597cb731458fa4b4a51a4c047faf74280044"}, + {"0xeb8296ff61166ccc0f42465b14415e74039bb5235665ae8cd02a5930f8daad072b3352954de7b196f2d8f64f4cb7f2914f6370a8a8734b25c02e06a3b0803302b01496e03ce7afd91a7660ae3ccce5"}, + {"0x6e6536c85b43c57e89c8bda0b0b0041f5ed14ac30daf0abd618c7a11a671d1d07efe885e137db64551fbc3717c0e9b8f45731e59271d82f0e42d6e0515a8cdf6f47a6f267afcb6d0bb6897da0a0005"}, + }, + Den: [][]string{ + {"0x126633cc0f35f63fc1a174f01d72ab5a8fcd8c75d79d2c74e59769ad9bbda2f8152a6c0fadea490b8da9f5e83f57c497e0e8850edbda407d7b5ce7ab839c2253d369bd31147f73cd74916ea456fffcd"}, + {"0xb0a1f1145e7cd5e35c021434850010ffc24b2c49e7205af348b606dbc306fd4454217a29fee410d1018e8f069ddb24da811e2ddd8964a0a74496d8786c10bd5bad5b3f5795d10a1d2b8f34ffa99b2b"}, + {"0x75c14b7554770e77dd8658cd970ab1aa2fc8fce9d83cc890688b286d5fb84b3169b20ec937622862770b7b62a4d5db9623e99fb2d1c22a1fbe9954cc2974b8a638fdc49a377211bd1d2987d14666da"}, + }, + }, + }, + }, +} + +var tBW6_633 = TwistedEdwardsCurve{ + Name: BW6_633.Name, + Package: "twistededwards", + EnumID: BW6_633.EnumID, + A: "-1", + D: "37248940285811842784899494310834635440994424264352085037441815381151934266434102922992043546621", + Cofactor: "8", + Order: "4963142838689179791878211236301121218116687802119716497817028544854034649070444389864454748079", + BaseX: "37635937024655419978837220647164498012335808680404874556501960268316961933409049243153117555100", + BaseY: "23823085625708063001015413934245381846960101450148849601038571303382730455875805408244170280142", } func init() { addCurve(&BW6_633) + addTwistedEdwardCurve(&tBW6_633) } diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-756.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-756.go new file mode 100644 index 00000000000..4657c6cc4bf --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-756.go @@ -0,0 +1,177 @@ +package config + +var BW6_756 = Curve{ + Name: "bw6-756", + CurvePackage: "bw6756", + EnumID: "BW6_756", + FrModulus: "605248206075306171733248481581800960739847691770924913753520744034740935903401304776283802348837311170974282940417", + FpModulus: "366325390957376286590726555727219947825377821289246188278797409783441745356050456327989347160777465284190855125642086860525706497928518803244008749360363712553766506755227344593404398783886857865261088226271336335268413437902849", + G1: Point{ + CoordType: "fp.Element", + CoordExtDegree: 1, + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + Projective: true, + }, + G2: Point{ + CoordType: "fp.Element", + CoordExtDegree: 1, + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + }, + // 2-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0xf76adbb5bb98ade21e8fbe4eef81b6e9756798f2e64bff3cb65781179d6b076b17683f3cd5042655e16802b1a5b1b5b5e386e23e2731d24c843595d5c79ca4b8b9179cf10cb86e782d614a1f78930c25aeacdc30c0008fb417dfffffffff2"}, + B: []string{"0x16"}, + Z: []int{11}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0xb99024c84cb2829c6f231ad6488f8ecbe73b35d177c03c95a1b5d4aff107d954726713be7dc02432d0d2d3f919a6b98b6ff46f95026f313a3f953d1776abdcc48d809cb0a92e2b7464ed6eab9312f612a13505b1d000072f6798000000000"}, + {"0x26bd1df0d7ae6c65ccce9c94a71497cd125c27c5fea6d502de92ee64cfe6161e0e05eb4aa16bb7f4c55960f84e03d6b986c05315e0dc296ea61a6ce0bfe7584381b90f97adb14083c7e63f8683ffffb35baf0000000001"}, + {"0xb99024c84cb282a010dde96a80e9b8571a99e3c121ae77cf5a598f3fd0abd199502d6d31fb5237042160e2f83bbff87df05586dc52cb529ee19d07248b4fbf241ffad1c2a6de71c88e46e4e3dbb1026d5ecafa4e300000000000000000001"}, + }, + Den: [][]string{ + {"0x9af477c35eb9b197333a72529c525f3449709f17fa9b540b7a4bb9933f9858783817ad2a85aedfd3156583e1380f5ae61b014c578370a5ba9869b382ff9d610e06e43e5eb6c5020f1f98fe1a0ffffecd6ebc0000000004"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0xb99024c84cb282a010dde96a80e9b8571a99e3c121ae77cf5a598f3fd0abd199502d6d31fb5237042160e2f83bbff87df05586dc52cb529ee19d07248b4fbf241ffad1c2a6de71c88e46e4e3dbb1026d5ecafa4e2ffffffffffffffffffff"}, + {"0x1eed5b76b77315ce6c7800aef7b306952f8658ccae70a80831fd94f251e13a45b7ccc7290e7ae2e14ef34b51df3471733e5650ac56b2e140baada4fc20270074f385fcf816086d73d46b785d5a289f4a69c36293f7ffee097d04000000002"}, + {"0x7bb56ddaddcc5719024ebf85e3a0a46fefc545c5c0628b194a34c4ba6ac12eab1339f794cfc8e22966cea64f49ee8f4675ef712f878e58793870797ac6d90c77a7cc163e6cef3cd9dd88b97adb140df8fcc7f0d07ffff8d09868000000002"}, + {"0xd87d803f042598656902e5a6ebbb571049b389b6a74b8bc73ebdd1ca73731f32dd8a54ba4fdfeada26f108cc45b54c92edb91d566097e064073732fff7dd09aa254f4a0dc2ae2f69fb52b5b4804e82d4ee97795b380000000000000000001"}, + }, + Den: [][]string{ + {"0xf76adbb5bb98ae2ac127e1e3568cf5c978cd2fac2ce89fbf23221455163a6ccc6ae73c42a46d9eb02c812ea04faaa0a7eb1cb3d06e646e292cd15edb646a54302aa3c258de7ded0b685e868524ec033c7e63f8683fffffffffffffffffff9"}, + {"0x3a1bace94385a298b335eadefa9ee3b39b8a3ba8fdfa3f844ddc659737d9212d1508e0eff22193ef280611747505c2164a207ca0d14a3e25f927a3511fdb0465429597638489e0c5abd95f49c5ffff8d09868000000000c"}, + {"0x1d0dd674a1c2d14c599af56f7d4f71d9cdc51dd47efd1fc226ee32cb9bec90968a847077f910c9f7940308ba3a82e10b25103e5068a51f12fc93d1a88fed8232a14acbb1c244f062d5ecafa4e2ffffc684c34000000000c"}, + }, + }, + }, + }, + // 17-isogeny + HashE2: &HashSuiteSswu{ + A: []string{"0x2693fe3f93094f745f2f924da1a4260675024d398700e46db4678d6c77e732927310a52e43b73de56540c9dde1f7896d115a7661f0e25e7c54754324cb2ab353f985c8bdaccf0b3ae0e6ee49e40dd2b5d8aee87356b60e17f9de343033534"}, + B: []string{"0x4577fc0edab719863d99d99fa7737b795dd19e05021cf50e2bfaadf8d3cf9670ba09ab81773af807f37f714475a819c9dd47d9d9b93ec37c70f3b857252cd99cac4151e0b42eb00271779d66c0b0c79e7f450a1fd85b66a23256679146fcb"}, + Z: []int{11}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x57b49e22a638e7ce6fd84adb98fef2ee37a078dad5e6db136e00515b7db476b3092fe24c634db1c19b32784bd06db0e1bdbcc194bd2ea84b5485485423516adaf53426ca54ef27fe07de0370f3473b05fab20bba48a8ceeb8f39138734a79"}, + {"0x4eb16246adf77c244d7c96da07c828728ec8cf4f73b36f9d3b8638cd7d5f00932de546ce6d666b6c1c78a99b824336da2aa7cf8017843619aba11c4e20eed632ffbd4ed04676972f223e842b7d9f408585f879993e979cefce07f6b320f98"}, + {"0xb0fe2b7d5cc6757f09eb475d4ec4eb2892eec65ebb4d0b73dffe388dc8b625ae1094586e7d5f12d55eae19f405323e54346d6e75fe5e30ed86a66f3bd956f2e0cf3b68afc427260f3782828672bc312081de7f76b025cb18780f79ccbb931"}, + {"0x63ae87b32561b93fb20fe607e846b376b2db30eb8774a0c741bc2c2525053672f753b6ea1b420fc0817c91332c754ee91bbdf25a5e5fb852314dc28a26aef1a6fc6bae25a0285b8355a97b597283baeb152f6a0ff281a7a6029551336d19a"}, + {"0x8e95e735b9b8a53ec343d0960e4ee6f8d38aaadd78fb413533fb771a3be16d1dfb91d669d0fdf927aa93c60a147c23c6b26b66cab157b3b1381e64646aae66dfc53e2698852470de8fb92e17b4504bc43249a9a2e7330e3b5e25da416f46f"}, + {"0x5f0f6d5f0ff7ce8777840d1c4d25d85f9a63f04df2479c5b73f1a95a3caf20143e0bf4e9412a9d9d63de7b03be54cfe59522fa2405cd2b02340479f9c8776d6ea9fca2dea8d6d71f455162a6e9f40b76311257170313a8682db61095c7bb5"}, + {"0xce64c0bb237310b05120e54a6ce7ca932dc2d6411b9761463cf0c31e07d4caf5bac19db735631219b68c1dd00e79f19e2653d050137a01218f5b1371d9a276a8938dfd36a0565662a1c60e970b0ba6ca1e330ca446d4863f5c44cf57dfe70"}, + {"0x5c79bf1abe91cef7276af031994044074bd33da0fdde5d1356095b3d02fa2d46345e935838131a84e7408ef41afb492c5a5cf8256daa4be842a0c4e9056f1f3eae94b3d47a78956718cec82b21f3e51338e5e2dea165bb52ed3c3fef55e2 "}, + {"0x528d835a2e6a30781df335a708c54aeb2b71dea9a27564944950b4eb0d8298a44b86f039ac8815883395a340deb72664ce9ef1d01799fe56b8141ffa816ff7ce020b37944db6c438b78a9e78e96ccbc63cff0f7f7e9366ee17fcce48ded23"}, + {"0x778a6ab417356eb65d79c0a0a1cf6d67f3de72168b1ac6c13f3f619fbb33e1da96b6b4b7f07ab0d82d1702006321158b231b405cfbffe44d033ba590dd218224ea7c800dfa1f00dfc41bc8d4f7d6ae966107bf5589f8ba66cfa90c23216c3"}, + {"0x4147349d36fc97c1ff5e168c56d665d0b6f1a8a048eb903e134490eac3b6d62e9c4741b77e0290a585bfa7a1c0dc29fe0b8000728ae4d7f01a849fde08e5c268914f0dee8ed42612e1531f958cf84126358cd261871bded7381b133541604"}, + {"0xc471c9e9bbb09990d5e6c9f5017fe1382bcb0835464ce01b69391ec611babbeca074b376ad1d5ee9c49a2214a89824f408b8eb1dbf80b9851997a2d7f4fc288fb2ee7c3c4fa9d52283e977c924af4c360c5332fce61c340d6af7edef6cfff"}, + {"0x44d18369bb41e08dea957a700307d9929a58b5565bb4fc9b985b6e98047cf473b636f6afa8ddf5cbf053e02477a616339eaef3bdf402e782850a2dc76555e82e8e803f2aa39f76249929725c6ca5d292d4b10aee3535e3c9d9368f01216da"}, + {"0xd46505c4491681e80a79fca2f3899ddefc5c765972f1ff4f4d20c6b8b89b0be5decd3e700f31ca2a0a24759dab83fd694a850902b3e14d656e4864b6fc2bf1f4aac08ed4fd147884840cb0cea7f94b0f923fb94ce65f77b5992c71e1e5038"}, + {"0x6f9632f9f15470710c2004132ef3ad5f5600087a3195f06fa2a1e69c0aea80a94e43c427cd681cd23040668e3aef649d09455fa213ab6364c58327073c8c798963672d092a60943e08d17f05771a42e6abc0d30ef3f1ec16195ff2e6d455d"}, + {"0x9a51e637dd926867d26d4fea699ddbf56041fb4767c71b5cef365a2a944cb79879168c5a93b9fde6be4d414a4016b01b70c039253548cc08b8309388a1a511ebf1dc8f8b9c436cb21aa944c9240a0c1834fc199be1153717ea4ad6f5cf86 "}, + {"0x52852129f19b369553182b651e1a006b282bec349935ab9fd2b392c7e43de42da08efb80da828e5bdb508c3a396e6e22a4f596da57126b2c654700cca80014fab35dd74dabc755ea253556e3d6a77d3d93f85b80b56fa4d4011970a59dcc4"}, + {"0x1c4076fbf2dfd41be9c3e3c24375f6dc8ab18fa163e8f502566471ef2432f6472cfb668c7b4d2e7753eb5181083607b70cac77be553df58c3b26f757f1c70c45474e0c72ac735c9e176ee3f4a10142ce372df6465e1e1e1e1e1e1e1e1e1e2"}, + }, + Den: [][]string{ + {"0x67ca0a05ba18be2717328e9da3d366da18fe119dbf0c150dd6e49daa6ed4f8de92e85a04bc69f045366c80877116759af4bc0c2a6f49ec158f0a2ba5e118ba6d26ac9f2821aa917978d4a606d940397818481adb5ab3f2c9670d2faac21bf"}, + {"0x461d07431e8397832b6ae980dc75548271ce6a87465b5ea5292316b8b1eb078b69e551472f41df43806e24ad887fcb1f551938ec0efc00499f7c3ba5bf7d8ec6d63a4ddd274aad64d716307d11a0ddb9d1c0f40296317c29455075bffb2ba"}, + {"0x43635d242d3fb85cfd3a36bfa1e3628afb5e1e14ae9f67f5ab735f8f6723bc48ba9c507c50e703220244876a482f00f4d7f2d022eccac8301995542df93cc151c10b4a622565832b8793de295ab227054118d673efecd6c50fea7b111606e"}, + {"0x86095d084f72a9be4c483ccc2c746e6ef6e26720fe2700df898dd5a5b20d6a832e2025d2d00a8447279691db55bea69a97e63e4acff6b5bc3254c3fa00017cb0adf4980a85af177485637c02ccc568a182ae232f54eada9391e3d98ed5ffe"}, + {"0xb017fcf26b80fc4af09015d106339becd5762ccb32eae4554d8eac08772a9335ccb7a8a916bd84caf4bcd4d5e53ad1ddf931deda6d5bc04c2df1682d31c696bf2321a2f005e77db814de79b98353ea4625962b9e30e78311ec0d9825e1f61"}, + {"0x45fb599a0f0a1dc49bb19803f84cb2e31e0c7c36dbdd187ab5bd8f024061a702d3e9dea95dc499b77fc32f4824fbaf91d82433dafbec16e1c977b20efd359e1334357a6a5b2d4b5c9452e665fc212908db0d18cfc0b5a5f3706b47c8868d1"}, + {"0x6b33147c7484eee118a499d769e8cd5067e77bae02abf17f8a47b040d39891089ffc19052ed287404aa3e3d2eb7787cd08bb0bfcc1c990a73d649cbfeadd6c4cf9ae2580101c1a1f45a90d32b0ff13e02b5836642634c7e952b6486d29f8 "}, + {"0x387e570f75f5fa085d262c1cb47c27f872beec94798787b8ea11debe75533ea5b0031eb544968899daacb97792dc67039eabcb6e64559a202f2529af243b2d7f993cf4896d9cd1af66b9cdf2753e483999115c0caa96403d360aa9841aaae"}, + {"0x1257e076f478ad94029dfb12ae9d928ce4550151c5a02aac92329f2ecfbdbd0a41567dc38e5fe5a0d5d3adcee3d1d84639145de0de9644244c34c031bd5d564a483ca617084e2829bd8e898733dfb99cc3cb655161d5854f687d9592c67de"}, + {"0xcb293e9849238ea68db183154dd3318b7a97d2c8b5911164a377e42468284ac8f489f97435e2ae5587efc9390ec8fe2dd55a466388491e21b477cf483333fa4f481bade0f0a80dc35c4d967dad4a5aaa1864323a8ab11f376eb6ee6440cd5"}, + {"0xecfd07101cf66ec654369b1dab1bb19588285083358b3f41fbcfa9a8667bee9f2e009a65b4588590ba71ba35bfbf3f11e0e38cfc02bf8e01475be7ce2fce4a6fcc8aaa3aae1d4696fcf86deff15d543c992e08aa4ef0822fa2da7d3dd82b9"}, + {"0x505e4b45c2fd0610b6de37cee0cb9a6e5434fe87b45190ff65418b316e4852a031583c3b5c28b4f78e5cdebbd7ac1675f1bbabb6bbd07ffad253349ed13c6a1e605856fc83288739254e877b0cca8c895a2119d0c9371fc59deded45cb1b4"}, + {"0x4356cbf741137297e9995a239f126c8e69898333c8a0891ee9ae4acb9f66cd1fb8b5c550d54b3d3516d27fc5ebb31b938d50d18a5d1fd92c4fbc246ae3a12886bab0e3b38692d26b5cc13372389c7c65df91ba04dcb040f2c8356bfb78783"}, + {"0x2d30af585d5961e587be65e1b61869b980d0a9a66510b0013800455621c06ab17bbf7cdb49df67795dba802f4a5dc215300a3a409408de7801f2f0a8e5b3587d478f94c523087fda1b7d9fce00d99ad124ae782dd5a6033e14141ae7af925"}, + {"0x89ce51dbfa7cf438f4174452a0159618713a55916e86698c00023059f53812346d2e996cd2be2ce603938b6e28add4df16fac31411400aaab469b668d9fc0efe45b04c071a2e09243a6f1c24fd2927823ba1b82803796b4c5ee8d14b6eca "}, + {"0x60380c3366f74e8a5f5447e6867e4d6b0ca3c6d01e5ad7bfaff113c053f5cada2ab35379044733a1e57cd19cf5ae16240e7bde52e621adad86a454c400381cf47f872d5b7ccf190cddc4a5477a932bd4a5e22534d30913553db82af7238e4"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x9f93a11a37f333a5052a497f2ff8959bc7b3e69bd5f470445f01d6071d144dbe992d4ea3783f0fe7d017f5dcc1e6d2980590726773e6b4bd7bc10cd999e2c38c2aabb90c484462c378b64918c1a48e51921fb837ac5feba926c3f623c4160"}, + {"0x577ef753befab81d08fb0ce7402dc357e7dcd98cd569530135f3ad339845cfcceb84f041cab594864b56060469cc8e0cefa322613061cf50bb7f8b3adba1caa0a522a5df2481f64cc0fbde989a13c70a8168d6cd40a30a342c186f229597 "}, + {"0xa68f14dfeb538700dd4d74482406ffae6be6396e04519ff32a9d0962b7250cd4a6a14a17fbc36032b9a79cb3f79b06d9918b4a34b8302120baf4757568bd3987d5bad8222ea01116c54237a31599acdc600517d3f733f5150930c07a9b8ac"}, + {"0x62f40704a8cef5860a7c1a0e953d8ab65ae5e0cb6e49d58da6e2501eabf797a77b043818a3bfa545a51060e24c3b7c2773412e527e1b72acf2044d95548b72836851a635e50c4c24b35c5a769b985fe464d857d16cecf2f8060374067589b"}, + {"0x1930bec080bcf38ef774f04e675193fc123f266b80e62e1b294b0978abeb31b3afcb02e33f65309399d12e3803fa052098b473eea25be9b9064c8821c0bbb90d9eba711b1dfddf00c2ae407d79382ccad4c6df7d43c160ed257138fdbd403"}, + {"0x65e5a193d3016af59101e156a7a886a3d15bfebab72190e437dcd4ee1a42a17f739c140aead0cf987e922daaf716fb7b36b61e0996fe6abaa4656b8a7f5b87f41ab28135a032b51957e955ce8efb83242cc62fe08a71dd8065c66720c000d"}, + {"0x7efada35b7158ff27d88e0ebb8775bb5e3c7f4224e20a223bb2acc78e0176802b998265a7d6473b22171bc9a57bf3943ebf43f71fd0f9006e5a7af6e6e76f11b949e7adb6b7d252bb4c36338ad539a9a7c77cea84280e7cd2964e5591d226"}, + {"0x29eb281af9b44d21986ba03590afd087e477f3cad3234825f131a31eab2adb59ed830aeab5e5156f8c5de90f81c12d8231604c9e25c4b358501edef95ed2926a79bf118f22d9c4f6455c8c7e37d618c9bc16c46c974437daf821bbd839df9"}, + {"0x47e261e740726acbe699eac8c486186ec6492f0adc2b3dc99615e874b4b7e093bcdafe1075392c49bca1ed7d4d043e2798c971e73535be10e8f4d6aa23b3bed69de7e75a8d3a8373e8ab0621582fb7cc43d2643095843d47003dccbecfc7d"}, + {"0xbd7d4e63943690a235389a6bb5d448042414a1fd9dcf42116515f6f7e5dbaf168a9830e70255aefd2bc14ca35eeb922039ab85ba718d3e6d23d86b08381e413ce18ab5c378c43675af0695ee62eb42790c5d5f89c2d0db6460678d5d7d2ed"}, + {"0x41c2f299e34019cb40e2af5a6bded90f03c9e6e0cbdd853e783f4f3d95935d39ee31fbb61d17610387b84ba9519c16881183a72c59fe7383aa5ae217b42b7480f8f058ad146edf6b4a7549cccea967ded9fd28d150274cee458208907ced2"}, + {"0x405da38064d76408c3adde67a954882f3c8fd36eabe3201a9dfd75629c8f4036c1d63831453109f54cfbc4cc8b9e5f663d3db51eefcefbce9b533b82e005bd9ee7af344ca3dcc40775a3fd24231ad6aa8ec93782ca5005c54856f0d85c04a"}, + {"0x5bafa78c01429499eed6e25e9349a6ca3d2e0ac1267e137174d00a6c433c6095e3d1f312fef70a5703698371ddd1c06e302261b4f6069ec4b78ad4e3dcb37b5253c0787566ba225638b446092283e42cbe85907b5ebff3b33c270a868f0c "}, + {"0x39c152b20238115dd4e6df5508cab1e2c8a7ee9eefdc292f058b6f89586654c8b3586b6f76e713ba51824ca6e2e3ac7a381a8f1746d7d5e500312a7c8513c46a5736425da606f7b9d34fb95df8e54ba0e7cdaef0079df1eced56133412cd "}, + {"0xfeac73088d841e8e555bfc8117068298c2aa3b88c0172c8339c4c507dc212472eccc77267a6946c0c4c260135b4a5f0665194fdf129bc15fc9623987abc4b4d251feb6696737b390dd48da1ee8eae6123b350c4356ab64e534709643ac84 "}, + {"0x6a9a250e9bafa906b1ee1517ad74a816a62c5706d13b5a198fbefb1d2d3dbda735841e67a0adc0ad30495670bd2b83953c65b19aa017ee928b6d5d195b3d16590edf554767224c79b07e803db87acc6a54b60d71b15eb75702f9168c5181e"}, + {"0xe1aeadc4bbd21621ff33dcea2e0ec99a6ea667741cf62af0494afde045b4ccb713836169de252f3018df60a9b42972f3ce650e5fd93a8e06e4fc281fead12a631e834d5753f175a5d76c2c3582caf46cdce6228ce2e767d59573c748ffe55"}, + {"0x7ed20aa5207c66a812970c473f270e99e5974d86d49be1e1976f669388cd568cf799f5c57d9a251960bad6c97dd3fc335eb51b4852cca361a95fc3eff218be4b9b46bfebfc552521659092156b85da783cc46a24ba5d1c1af9ddf017443b0"}, + {"0x7235fb0eb41c06b940ccf7b11788831523a2347562d30c2b147b7381f37a4a63dbae4794c8bd7d0f681bf17aa86221277496fd257af5814f73c8303e1ba09fb80ecf6627b00d453dc712e67aec504f7ece5f39d54f49f6212e792ec1b67dc"}, + {"0xba8193a4d3130aa424d39453c76c8ed262b2e2e0d07f453061b253ce779e1ba0a03f90d00a58f8d08c681204aa771512b68cd12d2dd4e7ee320514a2d5f56a1b8dd2a33c1d4d60a503cade7e0eafd341d8ac667b1c8ccee77ee263808a2c0"}, + {"0xf58592db221a5b17116ecd2bf86c7cb449dd623e49bf58ccb63baaf1cfbaae68778caa8b2f5d9b9211636f79b7ef12b9aa2155c4ef99276190af85a5121b9beccd7c747e153187c668b1846a179312b7fdccb9fd8273ffd3b058c2a97e99f"}, + {"0x2fb957ed355d384286b2f6153caad9da4cd75da2f960d2b0162badab4e6bb653f08a4ba1c93813fd4bdc0ed7ff19073696c16685bc73c7924f3f094e19db49cdce7365a991e22911fe27b1ddf631c5f8775210eee3de31057c27f397c5db2"}, + {"0x9a597c03b1977869ca1a58b04c6c7b5a8136d673428d8077c01fef3fcf1b7661dd2c9a0a9f258d60ac5cddbaddb91dc17e171cb4a48d32d3eaf5be484430496052e4e835781bbdb2f52aa838da2b488143dc2266adbcc6dad98b7bc422c65"}, + {"0xe19735baa44196f6aa3be94274abd8e8669acdf6e9d985820bf1adf34d66305e0a9c697ae0996b67513553a1a5b6e2c465895925873497d56cb7796a3a3fb58bea27d51180a658bcd7d81c7a86577ed8ed84b61484b70703a5be7ae16fce5"}, + {"0x3be0b32a85b89ede867e519b45827587ac1c9b3201628e5a499574e5da2edccadf907d9f793c735da5ff0fc3e60d3550653e133c3d1b467b5951ac65f8ac41b50e3a2e76024288847449f0d35d73d783c6a1c167f67a3e01c5894d10d4986"}, + }, + Den: [][]string{ + {"0x6fce5ce514cee5debaed37973056b6a3edfe727211c6e6a1fab570eed4f2a508e96d6b081ff4a1b1a8acdf79fd0bd33c663045955b8cc064b8b92b7bbfd15fec96bb04be80bae195d8d9d51c240630f776a199d13ecad6bc53f75189d614d"}, + {"0xe0962cd218121ad29e5d7490bf192c86380cb1f4aa91a0e3a86aa73be92a1c3e8a440a35f0248ee807f47a4239a421000433a638d113dca21313ab532984ee2abf3b38d1170fc51c7ae131c57a7449c65cfdd78de9c937528723d0712be77"}, + {"0x1ccc8c1978c03d019911928c1fafaafbfd603ad5590c6854d54c3ea722f18a19020e256e2d2f66418fd103b42765a5195c910f10097fe452c4ba4b5d5ce5a67ee3adde1a6b2cdf3b7721da38f676e97788cc4c64e2e7962fb81bbdc0f28ba"}, + {"0xe22f7cbf189dff65136339d090ea28fc60f120cfa26dd8433c6960b418362be2336be5e929dcc61beb4412dcb232db75be87f17b02742c2206620c090b9799e3ed9d988b69316875970f19cf14388a4fde13f176355fd16b702a250a65024"}, + {"0xe8f52882ce0a0e52ca01be901b93d21fdffae3d31b385750e422cc08cf926c7958a67728e2d26aae7ebf673a840d9d1f8aeb9e58a379f690461f8100817b8185a3e87401b650d473bea9733277bd2166d9f1d7f6fbe6711012bb354d2e636"}, + {"0x875fe99541a3b4273eb0e06ca68021e7b484844fe1276a3dd6c1ca17fff7bfa81a7fe367de671cbfe1498baea048a898dfd77b2d7ffbd4bbf204f862d8771bd35197f0575f6ddaf2dd8915747726e2aae3ddd49c58e47d732e7dc74aaccfa"}, + {"0x4dfd80356811a35a65acb00c46d07a392658904a4fc0cbda29046c44a833a31ed9850230c5f4ed0c1e1e76576ad104d193292821897138fdb5700b90c70041f6f5570cba9b4f4d7def07d469b4c892e87d2ec709ba01068510b911e9e8ad3"}, + {"0xa7f230aa84f2547cbe501721f030ed5bc4376f897cc22d1df86da38d73b27c3903e3e44109d24de87f66a029b5cfd5f68fa440f57de9533515f9912fc130ee39f65d7fb8da98d707cbcb268a3f32cb3b40ab7dcac9128d916a20625e28985"}, + {"0x7f35f1b0caeeffdd8711317415c54cfc5a1a04ab3cd08e6b4415b78b5760ce5dc99acd7c5a4a4c1238c478461e7b79c4f09bc4b7c9c42468fabcfdf142db1403d5b01a4cd818594dfaf729a18514e62aeb7a3733765836d2a9d893325c7a9"}, + {"0x9bce845eb9ff707815ed7ed3fb74d199d492671d29a3bf2072594b9154f530a311514634ef4fb471e883c854dde519b85f679d07aea459f7c3870ba31b1bd2c3548152cc0ce70241c24572d7eb65069b1a97f2bd155a4185ef91ea5659b13"}, + {"0xf0e88310ee09722be8558b6ee541afb4441bc1e77ae82ebcd5d792f6330980c3d36914d73138f0da01be4580c0c2188c0e2a010746b596d80755e71d07028f78bc29af82e7e5be87fb3430b1696810ea95758f3924d846cc0192a1e4f6e10"}, + {"0x8237fb8a7d102cfa45e7020363d892aa7380d1b5ee84b792c65fc2b167552c67623578c416e9922772f3ec99fddaef25907d91bbf0c72b8f0a0070a4d635a1ccdc78a8c6d4a175ed00a68a1eb0e7b90a6a5f33c6555486c77d4aed026ebaa"}, + {"0xacc8c17e87078f38e1056204eea4bd9343903c88966d0ddc2ca5166a97a99db4b66f74480eaf6030d42f8f23f00f1e7a1a6d13f086a76f04f14e98f12917de8d7998089c48bd860301813a95f708c6bd0417acadf80cb9831ee34286cfea8"}, + {"0xa9c3c892d49a5c3e506bfa242431f2b9f3934c51c40045e40478e1f4120da439ba6f0cc154e80bf1ea7ced993b7310545b6af11a6b3bbab611e648afe77297a776ef9468f51706bfbf60a100b53571a0a7361cb592a4f3000a45c013c950f"}, + {"0xeeade4edfeeeef2bc9f34296787829c99b544f11722d55db8789550c5e005ae27d651137cbdf9cb95ca030e3d84544dd21d7dca37bcab9f0e1ddc4cf633b5986746b0371648bac79367a9512396e9789031acc705cbff8c6d15d828c6bdd8"}, + {"0x6b6c82e8a5d0faec7af39bbaa40d86ea47acaac61910aaf01c238d8ac0f2587e2f993835b77e0312a3d23a2da61cfe7d68c91af4d0e24dfa29d5ce2c470c29c5ff6d89f060a0c0546daa1287fa3ab18a20cc1666ad84e3343d25997269773"}, + {"0xdb9102798323f938aa773da2a56ebce58aee6da13e2b10b8a56bea0398ad2d5fa0585d35f7b8b0e9076577c6e36ccf6f9d12e9018bbc8424d38620b874e24d4265bbf27fe0940ddd713e2bf225f0cac7a82c92516c75fc6d88cdbbdd58ec0"}, + {"0x3ad0edad38f3ac9e11e7c078c6e80cf48879547ea9efe567d0fcf53151b71697643a4940c375e6593b96a3370c56964ea3fc16bb574197886c0d9da0064eeb7e4121296069a4509b10f97a4b4a4943d083dbe0a221465711128d1778f332 "}, + {"0xc23a66e6ae7cebc4e55e5a301aa0bb92932e809fc326fc2a9e5ca5711241c8c77313b93e8065e8ecfeb3765a53e2b48bbbd6e27b960e76d00dd5f212f51c2381f6571a0a2d1bdb232ae1fea083b5573ebc76b53c5e8c53434a3e0ba80c3e4"}, + {"0x9dea557e9d9328f93a7a014265d3e7bb51164ef0a4eee3dd1219b918c457f7f0818521d498b13552933f9ead5b0b48d6b3db282c72ec06d7ca1721d3732f3fb59c6c655f3526db0cc833984a0f4957f312abf88133767cad4485c2f9b9af2"}, + {"0x9497a4421814871b03a96cb5d6b294880db80435d857c2fe9f4e97d75b37c795a1728121d66ce742793f98090d0c894f715a7e81dce84f594369b8bb2b9be0d482436c1ceffdc50efae8d85be760beecec788b5f1b08180dfe69567a0c102"}, + {"0x9ca415b1068cafcb60219e17f1350a1ba427a276689247978356bc51e19fbc7bde4a260c33e175dfc83ab230d17ed24c88d8de8c145213227d443192eeb2e1e4c61b7be341bd88638d5b44cedf93d445b344552c004f4b02bcc04b4c235e5"}, + {"0x2a27787477dddb1679fedf03a1e406b8df8cee954e12fd31e027d2d20f5dd6ffe6dc92a5c9ab16be8f21439232809c6187cdae5a5c6fb2f48617d22f6f2a719c5fa6125df02e551fc5c88bf21ff67de5c3cae2f8553bea742fdb7cc29c9cd"}, + {"0x9054124d1a72f5cf8efe6bd9c9bd742092f5aa382d88439f87e99da07df0b047400cfd35866acd72d83b3a6b7085213615b9cd7c5932848449f67f2600542b6ebf4ac4093b36a5934ca6f7eb37dcc1bef8d337cf3c8d9cffdc944072b5556"}, + }, + }, + }, + }, +} + +var tBW6_756 = TwistedEdwardsCurve{ + Name: BW6_756.Name, + Package: "twistededwards", + EnumID: BW6_756.EnumID, + A: "35895", + D: "35894", + Cofactor: "8", + Order: "75656025759413271466656060197725120092480961471365614219134998880569790930794516726065877484428941069706901665493", + BaseX: "357240753431396842603421262238241571158569743053156052278371293545344505472364896271378029423975465332156840775830", + BaseY: "279345325880910540799960837653138904956852780817349960193932651092957355032339063742900216468694143617372745972501", +} + +func init() { + addCurve(&BW6_756) + addTwistedEdwardCurve(&tBW6_756) +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-761.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-761.go index 9f10c63f6d4..33f34ae6994 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-761.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/bw6-761.go @@ -8,6 +8,7 @@ var BW6_761 = Curve{ FpModulus: "6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299", G1: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g1", GLV: true, CofactorCleaning: true, @@ -16,13 +17,263 @@ var BW6_761 = Curve{ }, G2: Point{ CoordType: "fp.Element", + CoordExtDegree: 1, PointName: "g2", GLV: true, CofactorCleaning: true, CRange: []int{4, 5, 8, 16}, }, + // 2-isogeny + HashE1: &HashSuiteSswu{ + A: []string{"0x122e824fb83ce0ad187c94004faff3eb926186a81d14688528275ef8087be41707ba638e584e91903cebaff25b423048689c8ed12f9fd9071dcd3dc73ebff2e98a116c25667a8f8160cf8aeeaf0a437e6913e6870000082f49d00000000007c"}, + B: []string{"0x122e824fb83ce0ad187c94004faff3eb926186a81d14688528275ef8087be41707ba638e584e91903cebaff25b423048689c8ed12f9fd9071dcd3dc73ebff2e98a116c25667a8f8160cf8aeeaf0a437e6913e6870000082f49d000000000075"}, + Z: []int{2}, + Isogeny: &Isogeny{ + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x48ba093ee0f382b461f250013ebfcfae49861aa07451a214a09d7be021ef905c1ee98e39613a4640f3aebfc96d08c121a2723b44be7f641c7734f71cfaffcba62845b09599ea3e05833e2bbabc290df9a44f9a1c000020bd27400000000022"}, + {"0x9174127dc1e70568c3e4a0027d7f9f5c930c3540e8a34429413af7c043df20b83dd31c72c2748c81e75d7f92da11824344e476897cfec838ee69ee39f5ff974c508b612b33d47c0b067c577578521bf3489f34380000417a4e800000000046"}, + {"0x48ba093ee0f382b461f250013ebfcfae49861aa07451a214a09d7be021ef905c1ee98e39613a4640f3aebfc96d08c121a2723b44be7f641c7734f71cfaffcba62845b09599ea3e05833e2bbabc290df9a44f9a1c000020bd27400000000023"}, + }, + Den: [][]string{ + {"2"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0xda2e1bbca2da881d25d6f003bc3f6f0adc924fe15cf4e63de1d873a065ceb1145cbcaaac23aed2c2db0c3f5c471a4364e756b1ce3b7e2c55659ee556f0ff62f278d111c0cdbeba1089ba8330347b29ececeece540000623775c0000000006a"}, + {"0x6d170dde516d440e92eb7801de1fb7856e4927f0ae7a731ef0ec39d032e7588a2e5e555611d769616d861fae238d21b273ab58e71dbf162ab2cf72ab787fb1793c6888e066df5d0844dd41981a3d94f67677672a0000311bbae00000000036"}, + {"0xda2e1bbca2da881d25d6f003bc3f6f0adc924fe15cf4e63de1d873a065ceb1145cbcaaac23aed2c2db0c3f5c471a4364e756b1ce3b7e2c55659ee556f0ff62f278d111c0cdbeba1089ba8330347b29ececeece540000623775c00000000069"}, + {"0xb5d1171d3260c6c2f4ddc8031cdf8733b7cf429122cc15339189b5b054d6e8e64d47e38f7311afa26134df779095e2d4161d942bdc3e7a472a0469c8737f7d1f64ae397600c99b0dc81b6d52d666a2f01ac70146000051d8e2200000000057"}, + }, + Den: [][]string{ + {"8"}, + {"12"}, + {"6"}, + }, + }, + }, + }, + + // 37-isogeny + HashE2: &HashSuiteSswu{ + A: []string{"0x10f6a7725da2bcbd3df98cd57fb04b0378eb7ff3d8fa48869b2b9ddf31d3fc46fa7c4805b5d4a79e54f495b52586a15154dca22425367989fae305ea22f0b5a4f979aa9f1d46f7cad2f21696aab503eb53485d6ccbfdedca97936b7702a7d20"}, + B: []string{"0xe1c43bfe2767901cf467cf40adfb7afe484d0d477552a8570a117661033c8dce4d56ccf35850bb0a5c646e4433a9b0e43b8701384b604cf95ffbd668698f8bd2f2739baa20c154eb7c88974a36fb5487c4cd8a1eb00205769d93924cfb0ba0"}, + Z: []int{11}, + Isogeny: &Isogeny{ + + XMap: RationalPolynomial{ + Num: [][]string{ + {"0x25398befd780935a98ddee5ea60e4ee96dcc3cc7e2f9f2ce97adb5eee13f1f1d35eba83968f25cdff13be2d0446e1ee6e19d332712d7b1f63509e090425865b0383f77a43ec7c63055a6631892a33b84b81457257314d13bbfbcc995aa9def"}, + {"0xbf9fff0b23525e2cea97716a08dd64003da7fce131cc13876e7ae922718e7c7b8a219fde11b35b7442d2f97a46f689a9c48636800a987bbfb5878e89b551db4b37469c6d446d4d6b59255708ea4a3f127b3199065213283b886788a53960bb"}, + {"0x4eff3f1c655d2a87d2d8283ee2451dd85a772545d9213f5dbe1f3410d2e21ac1808ca7876eae1110b33a6fd2073d467ece168630a242486579def540c85a2d66fec67d057d6091b08e20aaf4c3900a8c9f901844d51d38ec5ef4abb1b0f811"}, + {"0x1e9c0bcdf00775a750d64d31305f42117cd59252c0a3ed281e6b08cc26c3503e7d05a200d062300d173f5bc69a0c0fed0be50d429b72ddefc9aebb14a47596d061f1bd6ecc6a303dfd9b3a47a35b12829b3c40eb8012f2b68c765be361f50e"}, + {"0x116276c9e850399fd7f4da35f933e4b185e5932d984665cfb821f13cbc8726a455e5efa50ccc596ccddfe93c3d9bb016f1b95e42631f82ba4207ccbc0c1aa33ba899a6c1bb9a54571ac158f417dcf0ad4eff05a3ba55e9b9dcb0e5b01bbf218"}, + {"0x5619dcaec9c5296187bd9bae9507ba8e6c764f581fcd92d618cd9a9246e7fc50fc7f9fc8b5ac87c1897dd329ce72a85b9194b010ac6877b5ff0e5fc60379ece4bffe6e7b08d3aaba9a2301aaa0a77ccc80e216f0a8bb8b4a261eb76080b1a0"}, + {"0xc6b516997dc93cdfa17c6218ac94a6a91248abd4c6f43fa5b4fc697fc3a51effd39e55b261bc89b4aa71955df8380a40b7dfc1ffa29a01e26df9ffad6e3f3d756cf5b0793b92846b66d18057e2cf6366e3030836caad9abe69b47472abe20"}, + {"0x4159773ff45be12f91af867bbc0af2809e340c244c1e4be605650a2d3c609120ceedba9b1808a1307ec320948f88df769d1b678fc9de1c010756fe9464e4b5e0d11010524bc0cc292cae038ff9590096b71194706660fa88f6a001f17e4148"}, + {"0xaa0ec8348732fa3c9a97761f624ea4478cf6d4419f0b2f9dd9a54f91c5a95df61a058d1be7bd5c791e5b7f3a662bff96ad246272e77d2955ac52b817e161e397d8ade57c4f1be9df28eab1ae49a7d53ab57fc1dd84dc967f8bfb768731e132"}, + {"0x5626a46d9768ffdae515e2f43220eb9bc29cad1e6793bc78b1f1be6d8f55cd60cdc4d6653c7fd12024398d4ab901d283ca67c9798e8a1b6983a8a07db5897134b381dc523cdf9799229e5aedfd6b680cd75083a78b24cc73f6b3e515a00fc5"}, + {"0x68dd735eddf59490dad172f6aa60ae8110aaadb1fd2e1b708a8d429feca6b81381225666854277c93a5275ba75045d83e407ddc6a763ae980dfefa0b2523cd61362d7a658c622b5766e55a1b1d054b7199a9e0ccfac1d6bcfee34dff34b476"}, + {"0xf4d4ce5273a64c3463d1f51ed0895d3e20ea073bd4ca22febba741c47b6f6883866e984d62de4976b2890d5541e63af463d3b0b96b17b8b5821149389544a0c7bad5736bbe9b58395827786cd4f06f2c7c882980b290e4e5d7799004039838"}, + {"0x7563caac9e1636456f2e72d9034a59342e3a863bcce6b762e1b683fd1f9d7851b192b15bc2e19ffeff8560621285497077cacf7a160b59a22f3c3db6aadec7f650a575732b62884994e454ec534c0e955a38c42bb24a748129f53becb91d3c"}, + {"0x8250dc5250d43ba6fd216c9b07c2a8553cf26f9486c053518e2ef1d3acb59f2413bbfa33967b4225c1e3beb6ddcd94465c6f5dc1486d70853b86f092fa65e0d1786a8c3fb2f2dd10b309a98fc123d556e30c14737e05ed4cc7cec012423f4a"}, + {"0x110eb883b84c0238f7acbb20d75f08db04da7ecdf1c7dd8ed99d8f75c923154e280a750318163921759043a5c88c1cc2ba425380bb8486f9c3a9f9d716cdb0f4c2f1dcf96686fe582d4a88fdf21727d4342d7183b1d58de15587a280e1b16ba"}, + {"0x12187cc667349a16a75bdaea33e2993f7cd21d582124bdb248d746264fdd53091cb92188d8da7ba18e5ae858f047724f0d088320747de67e34ceff1e0199fb760f49dd57670711a1be6d4b6898f568fa44b560463b95adc10267acc34419791"}, + {"0xc40934532a6e2559a91a4b56f795bb6d7ab621deac562916e0fac5082c42d6ad331b9b83d4b9741925518bb8d963fa934dd3ec288a062437669f25104de2110e4ce5fc21a60590e0cbda800df12e1900d474846c0276c9f11084032b75a610"}, + {"0x950b7a24e3005b05c4d6cff3719f15f292b33ab2b6b52f5e0f4562d44233fb554d53bfc048ebc9bb5fcd3c92a88824de5ffbb5c1eb887c0dbb4fc5c20663dca7f66b5cec7bd641f751e21af2136f5e8eeb5dedf9d0d5e866566fc73de38afe"}, + {"0xd9e2458632e3e1f2a102f36965e3130f9d5e5eb0dce8240464bf79d11cf57f41c8fe66c04d820811d9d2af9f9e09d0265070fccc415e0aabdc0fd0ad081e12a5290090f531562d4c717b411165d8e1eb1a4cbaf5f239fcb6581c1a75712a1c"}, + {"0x122bf1411d59559e306075c9a9e73edba1dcba34443b235a1f3942a0f8edbc955d9ea0d9af240d05809eb3c0ca980527fd545e5988e6dece2da9e35061a2f637bd9f1f35aed13871ae23e6283c7e18e7459971cdbfde54507f7f22f281b63e8"}, + {"0x87f8706b78c7434a1e7d3eb3bd363eebf95d01ad6872e8660a6946347699f965417b8fff42df607d4fb609f414ab8eec9c02a4eb0e9b887a1765aabacdb3c1dba24cd1834095e31d358be65cde6d7a498163678ba1bc763da43c538dacda43"}, + {"0x99598dd5d2443bac8cd6e5c3ecc45cc4aeacf527c1b3567d300698a2ad073f5568544c5b71529380fd88d628416643b95c1afc65436bd2d12bcb4072876e5117b0e5c841b35a019fdffa973882e72a6118c03201210f4161d8179a77fa96c1"}, + {"0x395ccb482186b0d3462ee62749d639e3c946f14379eb2adfae39a686af0d4f512da5e99d9af6022457a75ece4bbad3c805d8d4a74640e02abc3ad625ef7c5b763d0b6c1251f66c991e087a392b0beb82edf72225a85c8d6466b035edbf2627"}, + {"0x3770ad705bdb83b47be929dc5dbd908ea8d79598a767879033c5fc2a0c7b91722c960bc130c0efe87d53576e8c5584a26c62a0e740d13db50d1adb0312b21f33b91fa89dedb493a757ca9aeed1bc2a4dca12793197678cc8fc57fb2e6a56ac"}, + {"0xb257db251cd766a618b10b3eb05d4af66e0aea31f5b3ad460f9d2ee1692d5e8bee298b3ff61841b1706de0438fc9e2081e54ef4b70ab63a355cbf3e06dea5b41435f7b3882192ba5af9b9414da295a0f419f4b95b543208c06f7ecb2cee716"}, + {"0x7c600c60c02239ce8ebf41f0319bd21e2552cd6d452ac9e8aa6608a38158307eab1e9425d494bbea54615c07dfa0470939e3434510c0d1241407c57b28097da2b181d27d3886d4856fd784a1d2dc53001117ecc1f7fd1e581f192e17b098e4"}, + {"0x6045e5de1830a58673c025130d7e80ca97bdf40887772da41dfa549d9869292e1739c1a407e6beb8fe2b99199b4e942be609f5dff7996e0af243b4b11f95f1786c4a1ca576a1265de1e7c3b2546ffa8a5bedea1ca96dc7a81f84a5e4c77a04"}, + {"0x1116eaf37b6d0408ff038d49e29bbcbeb447cdbf49cc259e3f4d48a852ae1ab74c117ff277ca19f08fdc9e4216d315b3a9119460a4f60001dd6be6807db300b5ea9afdd5dc63959275c79bb59c4f32368ea77ec4a4d15a476cd0590165bfa10"}, + {"0x10c94d5d3bb80cf510755331b3761f7ec4df14992881bfca3bc7c43801a077bcb294c8186153487ac19f724a22735b8979e9b86fe34fb6c262367c41a8c76af62fc7da83db17f6ed4eca215750b6d12d2b278585c654ec29d0937b7788940cf"}, + {"0x1adc9be54368e5538aea2182f9892b6fc66405c9a6ee59731427aad5ca1d09ede3e3dd2bcbe7e04c582d8b2fac638d2a329bef768de78a149589710130f3bd407b9ed5535d7b45778b5c1a5ce3957fb462cfea58a7c29dc22c876bc3992eba"}, + {"0xf92aafea05c0b551ae26fc31b31a624c28d43b2633de8dffa690d627760fd04ecc01e0a43cd2e7969263d703cde2cf4dce88410004356d82e535ece5f3ad1a38cd9d787aed584380a438416810b4e3d756be29b52f16db58cb885b83891e8a"}, + {"0xf6e4a497e67292d3b2ed5800dc4c716545175e45f04fbe0e16c6a905e5d2bf099b5c6d989299fa31f11352a7b0423cce76646b492696aeb3a7e139b8e5caa737c3cd3513cff20173437870a9943d5bf1d6c6dc4732032256fdfae43caae4af"}, + {"0xef6b9dc12aff103afb6d8f85d712538920f39072ae840d58faa0774a7df1f5a17e3f741298e9e83ac88fee4b5105f489e0b72b470b5219bf21f8af05c1f8f848904da49371d8c95b5cc896bf727d0fe6b0ddf965c1e3dd973bf8bcb5b2d932"}, + {"0x37bd2a9eca40df6fb0a16dea501ffc6dbe8b455c21dc65f29692d9d31a98ca815a302e0d0b8bbcefe63b793e4c81bd825704414613e8457453e1be9bac8a7f7b282310f4f7e8a281c422256ceed512339ecb348bc9bab690ee7db0b90202c9"}, + {"0xa29355f9bb4369fe4ed85ef14ed5a3c7307701d32c7f31d71947530f8064d5ec499eb17ae6d82853c8ed14eca3b3bcc1cf7cf698b7364a7aa6e63a8ddf20d34757eb4f206648f43a009d6c9caa25290617164247c47dc48ff1743446f7b562"}, + {"0xc505e34288c6805efcec5bd0586564640e784560bca7cafccb08a8b0a53d7c8d646fb60288a071f5cf1e2454d1ee1866365f32535d94e4a8cd0a05c209dedcc42eabbc105c080a94185fc6bbb331d3b77382a663a40b36098c030d178e3021"}, + {"0x110e5f69e48a34b6f6fbbf1c7525e873245669b5fced30ad78975d61b872b5d5e91dab7f4cd23259d7e04c517730240eaec702f238c42fae550b64d4deb617b0b6fd1beb61403c45268912bf795ba2d35d9e292ea1add7e535361761270669a"}, + {"0x11d2b5f8809e696da7ce154a2b558753626d70bd7b5067f4698f205252bde384b7ba440c014b56084035045d969b63e08179de17ac29216aa5592e88f8e24f8c1c021e7750d2a67b1628c2e8dab61965aa233740750f8d5a4cd83d55d4fd9a3"}, + }, + Den: [][]string{ + {"0x83be65e9149262d3203a99fc9235079469fd8d9c911ccd0f38c12cfa4c622ce757f49b41f1ea4687b29ee8e01212e58d238c956a5b1649f1c477e1ff8a6a6bc1f109dfcad55d5a778c8fb21cb49743c66d8cb6619163d013bb217cfcd15e05"}, + {"0xaa517d92a19b280dbc13f7f29fa923a05e4e8bb01bc2e44c40a96c6af237ba313bae0ea41f64bf4fe6b7d864dfb1c747ef73e9a6dfc1b5b4d299b0826c99357c1676f61345c05f9d8a532ca415fabb4199a33cd0a482c684e3c8c259d78aa1"}, + {"0xe1629421ebe8e0a16cb1565702c894b7f3a2509d42812b8937a081006435279fc5e3243489c3ae9448f42e0cc419c63b57cb203c524bec8fd171c1866ac52b773ce80494d0e2637d4bec5faa81b7c2c2f21e91d8fbee3c7f16cb858eb70520"}, + {"0x57980339d02e07fff4324765c596e2799aae01736d752ced8e6086fda14d435dcb1297ff21ee6d272be5d2bd6fc2bfc3190ac40dfa02e83990d5fe9a026656f64c6d99261dfd05fba525230d034791591e40c7aa7e73b38cbf54f627495f04"}, + {"0x807a9d43baffb4c128a86c128170656322ef19ef433ef5111ebf61c6ffa11be2f2efe09bd80e833650c2c6387de30f62198c8e02b2e812bead3143f06ade297f06f14b1646dc66cf282ca33cf458990ac6f3c071503a7932c19b9c48043f7d"}, + {"0x4da51c8bf1b1c0bdbf2c7825ef3b1fdea3b7fe74d8f897a874b2c4ca00b378d789d36d51d1dd7da1d548867183f030b9670a67b481c8fc587e8d9b67f363a4a0185cef41f30caa824b6e9411dd28dad32434ed655c99623e00314350319ed7"}, + {"0xd678e47f25725d1140f98408eebb2bf4db0ea59317a2e77c4ffa7f5e9c346d01387f79c929418fda184a7276209c9b05ae0b9a176d9757100b3713e1098c0ab035ad8969adea919a6200a879e27f01d2e5f2637dafe1ab78e03ac41fe61f71"}, + {"0x5d25a1d2d6b36bce592661279a360506c0422e78491c50618be960b85a7754b3a2fc8773c11d48c73cce13c69c5779d336405c1e236474d499fc63f0200673c4de4ee42dd2f2f295dc48d093e671b13eb94bb2a9534bf739c4a19098760a7b"}, + {"0x4fc12158207d5bd8cce8d1ea3f5c39517edc59e368546db2527caa4d5435654fa55fe40851cbd6c51c0ea8a22fdc4a5c0c180b1849b078b708a83b0f58edce813c6fd60f8d55063343a94722d0185cd273db90cc68a8daa7b2e2031557671b"}, + {"0x31c9b9108620d96f550a9746df4c3d85583fdb9d2d0f68a5bece080110ee8014cebe83083d1faf3b9389969a2481ebb2a98a90b207abd3743414a7365368e689738bdf5ba4b922d15f5dd1e2c40fe9565ad6338b0799d81ed1399106858606"}, + {"0x1117948c172e353417c135bb8d8da0d60ad5c7a0134739917b9f4eac2962e531e85faaf3642bee15183c801da80af4ca79e14256eb769421adc15349fd7a64d945f2916a9e673fcb5bf70f115045a314aefc405e3d277514bba37e932c814df"}, + {"0x3c242e9ec4fbecd4bb2508c41d59c4b626cf707a0bcee49bbec0b8a4a2777c5763c1ac8a0fecb629123f4c9648b5ef86fc81d40ec29525105ab3852df29d4123e143f005ca3445d6a5bff17dfff186eb5f4e257790dde0f1a0b35b7c519b02"}, + {"0x12004baa7bf2797052c48564d94448af483b791a8a58bb0fdfac7206aa30d90a19c75fa26826f6c0e50883fb357d08a13eb13f7b5c64a4a25dcf61cd4c2c04de84df8239a04ec26af80bd483d5843ba5e761284263c974e3877bc21f1dbc197"}, + {"0x40fb8a400112da16c9c847085bd345e2ce2b11e484e5b3361e5e12b0e9b99eef6e1a527cdd123882805d27b8c39737634b9ba27e953a7f26e7bbbaf3a92eaf7cc3496b7505c67958ef08de00740cf7168bb49e7be687c65630847ec9cf64c9"}, + {"0xdb841e9665a8721fbe1361196f1abffbaaf8e61aa13128b8595719b3f8fb1cbdd3b350ca0de1c3188ef820ad8490998744bc8a5e177284ff0d43c84428deee9d41f7f1a042eefb03d02cdcef7653fc6be44f80826df6dc54146f14e3aec5cb"}, + {"0x86d23a6f45e1098d00b8ffec6b12be016250481227e1f2d81b90c3e1cda0ebd2f4efdf381c8bb523f227f275bb681f78a6c95523259720ac3723be36b282cf191288be453008a231c23b67db1eb959d0e149a8135000c5b44ffd1ca5c2439f"}, + {"0x109f5d1ef11a74270bc231cf7083d7278ba957f6d56fbfb3e8fde415ec551664198b8505ffffe1e15dd118b0a4331a8c17a3b98b50643e84dda3165037e42bb9c6019281a3f4be180a738fcb5168c9d76140a06e27d5089ba7f377b9132a05d"}, + {"0x1f274511e3255d4b4a9ad16cce613ed711a05c14758fc9493891cd2d7648807dd6e4556cad36a50945e3e31e4056d27cd49d3dd9ad86701305943bda400c3751bb082764aeda446723655be92a8100fe76f0c7933540daa8afabdc002806b4"}, + {"0x59843e330375000405b054eb5a19aa651450f2c5e26bfaa5032ad4778fbfad597a13691eb8576642f74dc05243b74750701ca40bd7308dae55746104e41cba2226d91cd70b541be8944e403b8930c835f8fc924f556f0274dc8c241c1b1fec"}, + {"0x171ec81a25db9e6028013ed9a5456bb33310e6d3198f21a8e7cf9ce447f30b8830709b9888078e38d676bef24209e26fc81cfd8b80a13d17461841767498fb47afd44ec6239c843f1312f26b0c8025f05f13e8f68db73bba437745b394b0aa"}, + {"0xd1b60042578201579ee9af7daf134f171ac865a3c7165f7a5732ad4a9f2bd301d10e4fee128e96037d468e035e418c46d3c9a11d00622b09d61761fb05f99f2aa2a9ce622cda95c2b321122e7e5c5a1f664e1c44fe46fc9db8a745eb0837af"}, + {"0x6bded64c75b35c01a8313a4bc6695d762020056e0fe4d87677e9088d5cf5585c8482facc8637ee4e619906637a26245ee4694f78d1afd6cb0071844e710d7498e924478db66d35e1f8eb480537873ace7d72c4cce9c5e409e93fd19cb4390f"}, + {"0x409e187b5c36bc9b744db93e60f4f26fe820f8f9ac1731a4ec4220adb0ad1d92b89b69bdabc9bd1db1b99d029c083a5345d9b8681866f3100a77a5e69a9616a7142416b98a84f701740c4f95de3cdda3a198e9861b6cec6e26255bbe772da2"}, + {"0x10366573a3c6655de24305051f27ed68efeec35822c0137e5e2b286cfb2c535c78ff42dc67539545ef780f8cbd8044e9f96e58387cc4f1ebcc1fe836cf359d02e71eb64eb313279edae20943c0642d57338e60b031adfd4bbb424dda4d2872d"}, + {"0x4146d8d1bb6cb1c43ded16f5c07010cb808fa767a0b59047519679124a5a1ab4a1f2cee179146460ff296440254807b842c968e364611b56d0ce862f3e4f79a9d3dc0d7f5c0a3aec81ace2208b3d6710fded09f7864d29bbef79886571cb09"}, + {"0x8f94d7b08b0685963d24fc8b9281d6c290a4124e987136973122a30db0749c48ffc8fdca733627914344dc1077e20be895e36ba93ced63e9792812913c9762277d8556ebc293c4cfe6f89c5f7358e9284b59c1fbdd37b0e066cd8bf282b1a9"}, + {"0xae19c1dd2ea2e1f7a7e0a05a24945897e533f3bd719347b3050acf6d68480a01d574f10498145d27d505bdeb3bcb9bcf931275c48c6e1a4f18a46b7c03d9c0bd458032e2198b4823371c9ced7c68826b05a1b94f09bcb2e16217baf4c9a2b7"}, + {"0x3937cfd56241d0c6ece2dbbba9fbf5b7e5e4432feb90c2641baa78ee87828a5c3659d9f06dc762dd5d91cb5fece510f4d29802513a25db34f734d4338a4e473fb50e4cd4617ed3a93f2f00f00d543522dc42a4255be811e68869ffcf502f13"}, + {"0xf056010b5a01c99c3eb8515f0c20cf81567cdfd453df66412443c4853dc34a994126d11fa6c1a59c5b3de3d5572c95cf0daebd76733cd1a61436adf73571077dfcd4ee452ef07acba0fd15371473f7c7127b4dc1f97da8227b87dad9530dfa"}, + {"0x1193e22533f0c5ea8a191ae0ae6055d62c68c59d05e3dd03eb343777b3615485da3ea5174759b34b9f486f97b6657580d810f573e57ed46c8649c002a6441c3666526fe8f7140b870760ca5be04a3339bdfc10d996752c61819e18d862f868c"}, + {"0x788926be987f1259c031ac18dd6771beef4ff0580dcb455bc125fe1385113df0cbff993559f55752ea1502a3e8e84087b4f9531a48e939cdf4f41f31a10198e9a82cb07f0d78e82deb8aa18cb2e3cee5319d4df2fe4f4bf69201e84fd2f575"}, + {"0x66be610c58e904d4b5827f9b746ea5fcdf60f2e66e1ab240fb5c65eafc982d5e3eec9134d29b991497cc387471e05462a1925828c6e296c6f1a965c209f33e48cba22997fb02d315c63aaaca45b6ef7c0beaa2a96da60e839cf4957d6bbcc9"}, + {"0x3487a8ea28fc7b67a089b3e70e5eb268ab99485f31d1c7d7f281853c4e0d1e7d9e0c9521839d7286e6e1729df7da275bc576bbcf8b1e00d1e2f996150fbc725b904bc0077173d29ffcfcf6e03469176987f60ba39a8f6ee0c29d448a7a750f"}, + {"0xc68234b4d6bd5a4a37d13151f8e0f13a90cb6ce91d72e9ae916b2a29837bd01e5d4ce2adb1d90e883a1f6b5ac9b25ff7a37cefb7d9e29fd88ec1e9f3578cda671ce824b3253bc69319490268f60bcb93de665904d44acf45dd4c19861070f7"}, + {"0xe84f9cfffdd42f1f808768789dbcfcc30a49ab979995fda69cdf696e4f6b8d453573937c1801d258fcfbb3836f79e39ffff9f88084f61369cba6ed1f84bdeda53f1d7615f2971ad92d6ca0aa810ee44e94c6c5df4aed9b849eac77e0ee83c0"}, + {"0x496a56f15bd023ff76aad9ec934a63320f3eb03b60d13cc7bfa0b88d00a6168dccec5cee5fd2b01e059a414a876a757f502701eb366739350845b04410654aa1027e22511ca88e182106cca0b8f36489af9fd429a7e7b8b57030689b11f45e"}, + }, + }, + YMap: RationalPolynomial{ + Num: [][]string{ + {"0x5d38ef6582e5d7a838009ac71ecc25a6c64fdd19f4bc0d74af29b637cf51a14f40aa1bfc18a0f412ee1275c5211795d5dabcb7f7512dd4444f8725595ab965db9a2a330376fd7467616cf35fb20d8f65c93d02c1ee651929bfef3a02010998"}, + {"0x4dc036c1f4c016a18f48ccaeee3d1fce48ead68ff10b5d267a4e8090ef866a3fbfc9c826b1794ee575247585a3ee598e23e636b0e4f8a54b1bd182ccae0edd530e76c56b88bf2af50ac380ae79d88debeef0b16ca39f174df39b08284a51bc"}, + {"0x3032bb517e9743a55bb8f645f20cc63ceb8e92584534d6b157d461483dc394441df9ffd30fa13a5bad96c22b1ba1c0bb6f88899d3133f4b56cb1fc503627425bfe13de5eed7f9819a9afc6944c7537df20aafc097ad6650d17ae743d1cee77"}, + {"0x971c6e281c15dd21949eebccdb904c1ce2ddb0e4b541c93acbea7528285822fc660b6fdda6b92cd4872bc83ee741775f2d9c3a5765d7e70ae7ba2de60c3c73a1a54ccafae655deebaab1c03efa9bea4f5f51a718088eefe57f0292b5b14798"}, + {"0x7ab3de0b6540aac0819b8e9e40d8ab1599106f942af09c137f4242c9c26ea921dd782682c76b266b6e44cbe3843b0ad523e02a80d2af69efa3eec5c39e58566df3cd8157a20ca4c7383eee7b2c32f2459464abd5b9ffd5351c3d881a41dcf6"}, + {"0xfaecdb4a216f5c7f32b59689f8faa85d747f95adb8920419474afb8d55def7b52682c26fba23bdea292ebe6076a67e9ff4740cd2c0d222dc90412eef46c7902dfde4eac64e1d7399d4e2fa756be80bccca12b9b64f0bd9ebb616458aa651af"}, + {"0x8397c87fe6e56393d59e832cc69bf1daa706aff0f68f038d9cc3049d41dce6557e412256d8cc41d57deeff92852eb959fd7d2e8bbc39a3bee17b956ba9645f05e5cfa1fc66ce57d80cdcc9ae937c26555f0c238f158150aa6aab8494457159"}, + {"0xfd13e17f5b33195a3e4c6d3ef8d0fa3de081bf635cc38b22101eebbc673ad40e5212a5cae0285df75c6769b83d84610f3ea9b5a93dd2081ceb23cf5834c7efb2e39153e8d40277887343b630410b7581b9629a92f85236e04d1aa471383f36"}, + {"0xd2a831f4ed31fc9f53cf9e502189be67bf2ef9a4f1a05187e18f2f0158c40e421e8e747c5fb1c706c7830f2fd8186e99bfc4ee25a2f5a2e9adb4509e98c131abdf595fea29a48cadf69d57c9b08d71fe6661c6b597dfb30d4c4d83cd504522"}, + {"0x10f83707440c9575bbfb5e4779d00f3adab570857d6b2811efc6a36563c05877d23b8aee98b99e041a5d5677a5da2d59e16d1b9918956f720339f140f4b09ee23748dcb557135e538413f14e78199b2a7f5cc106c644fcb2ea142dce8f1fd4b"}, + {"0xea00809253d1081f62d4bca37aa536bd29dfa9d57ff211e93bf7d291dba621af65fbc05fea7fbd771e330b360ac2ef1c86f267f7d790a4c49b3a35855de520fae53b016499e2e4d34572ddf22182f45e0427f4e2af38dabca89918101013a6"}, + {"0x7a484843420c7079e43d6ec50dc2f94949b813b16c3e517c61034acab7ff1d212d5a6599460cb97a848e98ff86b779b57b9230fafdcb310bce8bdff32facfb7e8ff5d5a6a141e9aff51d0638810bfad02b374b56b167e1ce274d752d80cec0"}, + {"0x549b03fc6497586f83bd2db5fe2657effee7d0e500b4e694f966895bffda5393c27db4075cde98805be3c10994e10de502ea076e860ddca3dcb79e63ce6bee9a1b6703bcb605c43087318f0d9036c301e7841d0c7b032de1661ccd715d16c4"}, + {"0x76b1f83abc358751cf969aad2c4e59899996d0dafddf76f497fb693264670c7a65a536aae27c30bb34d8511d64c396cea615ef78c116d62dd81eee16e9882159fe92c56df94c27eb7aaac74e5a8ba04244451552360419feee867f6cac723"}, + {"0xd92f770caca73c3505c3a4e58a7eae19c1851ef9db25f07a785cbb78e4f4aecedfa7a5a5046f4622f3179b37ba00c45cc4bdc6b1fe86ebe49c8e9fa4290d257bc319185c825b66e8b180472ab7f80ad3c71a1dce9938ede56e2d7ece900d05"}, + {"0xfd5ac3a657102e0a54acb58d0a04e488934116e5d876c58b86a4e35d3af411aa83627651dc8198133a4eebf14e19286ef5b491286e562465445f465b742f94cc23dd887057cbb808afd477ab63bc467215b1971ba490fa2827e0d81a108f04"}, + {"0x10d6bec8b4dc04bbec4fb4149db3eb29604aae9f7a45f258015e66821b85b690cebb16777021aa0cfa0fa34d3e1f85161d11bc16183faa6051d6f726d0d26d1e7772543c32487fe27d852626b42cbd04256b5f9f5929cce9e84ce3a35eca852"}, + {"0x10d36f163c2f08d03557ace6308c74b4985dda1228f121e4c469dc37fe80c9b15fb569f5620065425a517010c93c0957a3bfe5b960d77e28d9bbe429518b494ffd268084140d17ab534b79f2bc5cfa780e5cb6fd5857f00251437d184fc3f36"}, + {"0x94302fe280a10e8c5c6601016f8744495ca119f4195d4eaa219e74506a25e93030a47862ca125d213b260738ab01882fb14e1971bd92b5c59e8f29172ed2f4ae8c9cc142a1044b8d3219e9bb292ca5e7bb3f5c0294f64a67e33642c8cedebd"}, + {"0xf062482aea1a30b121edd74c39fc070f3981682f0566f5c9143c65ef8f33182291639e5ab1db19070742f6e39d7bf38f66171536a9f164d1e7a5b478bcc9638a908135644b4fdb979659c28be6bf01b89adf6dbe5108084824251a5eec8f4e"}, + {"0x867a161c059d9df42b5fd6674cd91ecf88204c3bd498d793b67baf81420007af8dcf3327ac0402d6a72ba8af92b62c55509e3fb37bf8ce4bf048104f61229f8b52ee9a4bb45d6dd2362173e276d6857d5adb961662cf301618899b2c8acee4"}, + {"0xbac156f5735f9db804c79b3be77614d0365928205198a8405fe744332cbe784d46a3754dff8864841a2095232a01803ff43459f8904e6158f003b6917075bc588ac2424bbb9546ed2a7df59247dec3675e3150a892d82d592a2dac11077577"}, + {"0x9db7d39ec19ee775c663f000d726ff2373d9355bc9bad384d0f297b0a5b5e3173f6ba8dda95db0e29f6440102e90ee524a30eec0be66e95780a25e43123ee678c407256a77ac16334bf85e2ec00871599facc241bb42e6e8aef8454bc2193c"}, + {"0x5d679b51a45e040c495721d309dc5d813db4670a1f71d020beeb499fd28e420b9c46edbd145d83fc514c5af80a70690b8ad616242723b732929ed3780050ed2802adc6bddaaf8180303c7ed3723c217acd225430db169b18377f482c9c67ed"}, + {"0x1083a6218e20e989bd3d5a8dc6b72927ee61b6f1ae6520d5058f8414abdae3dc928be29740397c34e7c47099981a6418227b692bd23e6d8e0f17c9ecdcac75fc71b9746675772b093583c55451077c29cfbcfc20f10cc3c33b6d3fa576fb798"}, + {"0x2a2684b5ed4c54325a36d5472a22ddb44e499780360ac833a0d88b5bc6ae75c58a7f62540701579c56d530f8d7681c8c784854e40a58816f5fbb6432eaa776534dd47b3611bec33b6e87464163f7e9e44d485b2e47d9a07e64ec57dd29cc4d"}, + {"0x47402b33b50d3ddcf4a15f745e0102d11be7528f1f5996e4042f107bd090237bf5d75cd37f0912d86e971ef9452cc46312b7428a952dcbbe959fa1d767ecca1a0b36e1e30a30e0f71dfc457c548a04390371a2221556232dae36edb8da064f"}, + {"0x11da53c9271b02c7158fb2ee86ebdae385da9ea1fbc07ffd9dbd8c3e8aa15ecda86d607469df1146982d7261aa35c97b7d74d09bb9ffb479f935e71c69f3c60005dbca5491a4954b01fb413b5e506092664ad2cfb727419b104acd72e036f7"}, + {"0x536cf5aa2222d8de443b557d093c9f29f4a16dfd168e6afc1382d9841697ffd7ddeba4d099d2bced00a1aa2285b1788db932d59fb3fa891ce97d2f74e9475927fd9616c5594b9152e99dd586d5ca8ae8be11cb213289ae895cbdd4b2fd465f"}, + {"0x1da860f7c3597b35726e87cb3bf0b209effb0ef9ff5b2f116098e644235ff06707de8383e4cedca3defa727819c6a7fa4574dcca3844096d8e55ec3405ea3036e724ad26480fc08be1d562c7db9a0e0795b37e337e09e16c7e5033546ee8f5"}, + {"0xd07de606072f1a8a527374c766ddbbf30dbcf9fcc9ef0dbee36409d153931702895dff106c34aec8d2f6b85c4e2b310c4a6df78a37e45b4cce27062ae58f9a7ab8b3e8d7b3b60585903ff5bb83b5861ad82d740046741b91f7b951a5dc3cbf"}, + {"0x2606343340db37698dead78d4cddcaf70a6850b005f27101986c5c402a6d7b86ebaab95f8345807c243ae39a51ad91df6b27ebd90b4aff85afec988b3889012caa8fffad0c621eee9993dcc69f370fc96b5e854cb8eee096061ae383c00b4c"}, + {"0x5eef4743e715650a29dfe5d51bd349b00d506292b178708638d69fb99ad660056b8b80f206e1d507b863f2b1b7a26f3a2c115ad138ad6aef6591d911993705da206b6107e5469f8cc1d7623bcc867c10fc3bf41c10b4104dadc1914da7a424"}, + {"0x76727dcb29badfdf33c34dbb80cddf85084d5def7241d7ac8b6b29fa04e1097c534b5272704c75de0b439d26ae3089a3db2899041e275f3bcdcf5364b8505ecd98cae322ff7b37fafba7a8c9f7b81bbead4e4831bfa37dce31ccd4c0ec0393"}, + {"0x1121863773817cea34fb74e529bb85fb5eedd5cd253a9b209f248b1095a79371ba0d58cc7ab19fe62fc91bff7d55b99a1c92b6f299a157d6abd061c56b99a40f4ae8f571ca8bae37cc46f7d72e31283358d089786ed293882489deb19f2fa5c"}, + {"0x380aa09030f5968743a51f91b9f4f2e76ffdfdf93c0c1e481db8f7ab2f12b6f1af4c65388b2283f4dafed85cbc94f02482426fb73d27c1f9bbb98fd1ee37baf2ff25c8d28160f91cb356679908cc289c5ddd7c3b0c10d70ce520877d6a5ed8"}, + {"0x3d32fd2068147a3f7da278555ed406ade542cf524e674563b2cf9b4e8bded523fe0c6cfa7ba4366049ef1853ec49dbec71308f9d9c07fb2c92669f403228ec339e9c0d854340e32a0d312366872b84850b002246a56dc42da0d78a794f82e0"}, + {"0x8d03083b6680f456a6ca2f12731aec4d9bc3047f1338dca3dface56f3e5dcaa248034a8008c1cb6e2103cb759d3ee7f9bf050ccf5fa589cf3da4fc83ad8abad35cadd716d51de0f823f8874aa7b1759c1265d7767ce44a23e0fa26cfede36b"}, + {"0xc153033cca117585a8e7e559a8b5afee72d31ac7c96ea9660856b636d26664619b0d16312f43c760798af878a41561ac18b87cb636c456d653b58d0343cc76cac997ca14928b935bf6c9b9912d6cd88ce3ad7b2525c09727dc2e15752ff950"}, + {"0x9e424fec6f5e28209f0dccf860a5bf271461173cb2f2c63922b520ea861c8b17876b00af0a926be498559104ab3701da59cde8972717093092fdcf0f4f1cf5ef798db7f5bb86db0db37c4ded8e979869c1a62aa3e84f2091906b0838a3822e"}, + {"0x1f7b0fd3b4c9a79f8302d026517b9018ec27da4cae421b702cf5e7c4923c438d89a24c946e473af82528298e92df34b54ec696ef86299d10c3fd8252b951b2b4dfd3b829a59c81c6ace17f6001df90e6be71bd5d68d42de866f3ab1a202423"}, + {"0x9402f37c7ba1e44be19ae14fe91a6545acef0b2a0a5e36b28179853b1f2c7f98e988945246a9d0bd433602ad0a75d66c4ccaad92800b997574767815e9ace78b11abe421571bf819ccdc2068accedae0e729315b2a1520c7bf579272dffd49"}, + {"0x331d1df12f90a78ef9e864e208ca152c9de1601075da588eeac25127988d0f04e16af1f2c817b2c33bfacf0c4696b86f5015b0f66c40cdb768aa2eec7bb555a17a245f7136ff01da8de4970bcba352e698e1f350dd17890e07447f13f2928b"}, + {"0xf6fe753cc6edfb75968c8f6b8cd121a06115ed350ee30dee74f5bf91816efa1a47d450f52febdbd8ebcb5483c9b169ceae1125e2f69f254cc91e9077d7e6e409b9e80ea5e76ec5e6d9a84a25bfda45ab2555314aa4a458243fe5c225c1d149"}, + {"0xc1034618a75481d52de528c17b76c6f30c350df5827accfe92a886055129790032d1cc01eac8727255e1ba03557cacd704ba2912a0737ed16a69f98bd196588d474d6cad779bb90d87f6743a87573f081a734090b05d1a591bcb6d4526c7c2"}, + {"0x19ecb6f5a4ad4557134ccbd3ebbbf4d3d0062a9a5d288da6f0e21bf98f2c04ec673033817c2ba1e808a23e96b99e945ce33a695884cacbdf15991bf2b9c4b3b9a5133888ae5f3947be1f9d499316f170f8218494d43536d883db4c24584adb"}, + {"0x32f37e3a71b888b9fe0a88c42666b32112b5444f24cbc4d7a805dc02b4538e0bf86cc74ac277acf8acb9dbf815605dc54a746ff5595cf472eabd6299597dd15d479dfb59307169b2b2f1e50c9c6d83d28eaedd5569d7f6f1f40657df2614c3"}, + {"0x107ee94600281e0d5b68e55349f03c7b886c4b2fc8a827b7a353fda767beabf06fccae229fc2bc576b49ab29263c7d21499172898b4757f3b44aa54fbe99015cc1b263d929c94b3a7019490d6e28b2c7475a7977d4822a065bdefc470912dc3"}, + {"0x3b4583aa3c1f1cdcbd1b268fecbd5c85c46d7ecac4cfa94d2ed766887ea79549a9580d8a0ce47039ff60bc4d3aa202435af74c97403c172ece712bf15c246650d6612baac5f7019cb0bdc7175840fe1d7c8c2e9d5c8663cd12a62501e9164d"}, + {"0xf6eab8fc5a94f484333df010d6f2c6b620520cdac1a40546769fa2b02f9d6e466724df638732a4eff5446436296dface1495dcaa6ad4e24b3a14a0c6c98364d2022406167ce327f82da7c59056962b5238085af38db3f39758e9d1bee007f6"}, + {"0x9157bcfa227476f05aae9ed56e79824236cb30f1f47dc82a9648703881f75342ea4dd3f208102bb034ad52f7c0a64d33806df1634fc233317e55e17c70abec3d1fc16cd473e7a1693dc312a5dc498709166bf78607b2726557f1dbfa3af42"}, + {"0x13e95f1b69c1bb059b35da52693903820813354d0c2a3ee18c0077aa967afc4b7115d0fb99e814c7b256acc47cc4f9995bb0df178a604f5ca838ace81cb080dbd40e67dd731e8c54ace47e999d79841e38881f52e8ba7eb82420e457069bc7"}, + {"0x5d6d5a496bda19771b6fcdf7cefd6dfbcaa8945fe445b5223cc538ac2ba0df97e495af83fd6f9c272e3e4914ebf9277380079d9290a356d9111bc382492cbc13ae4ddd0e0d7ba5a1f3c117569a2a8e96d169af588d1d4085d0d801a598d121"}, + {"0x12ed009e830c3052d44ec9cd6787457249084772a2cc3118ce49b1bf668dd1a977f524abcda366867cdbbbdbea655cb336d2a088df78456d3d21df942137d25b1343edd948cd5e3b49c76ad5937e25f032d00fb29262f071c5e4d0e512650a"}, + {"0xe3da5cd6c4e06d21025932bc0ef3fb4863115ec20420cb77b2f8017df249e00422a4d2dc652400c82dd4dea5de342e9d61fd2f1f842b9e5ac519eb62860061562526e56e1087eef9ce359a629824f703f5c1ea62cad6ae10980a7b6363064b"}, + }, + Den: [][]string{ + {"0xb35848a97889d06c9d137621e2f283fedffc9d4fc1a32da73338a90d0a46fb076bee393363f551ec5bc14317a92290831636fb97eb217a7dfa6e64ee0250a2f0ae408c60ad721aca20082b11124ed0af26b9b472706b58c8e258dec46457d6"}, + {"0x11bd48159d3f3f0a15e56f4758e253a1d2b3b14bc308c858f3837abb8e3868658920679627e8a93ad269631ef17b1b1693afc409afe41a71e49f64a1e2535fea30f085d24b7b6cf9aebcb322358f81a34b6599c88bc90b978d0218b755cf2c1"}, + {"0x1c14b675d0ee3fe6c012a5be16d84618112e7838d3621e79f62729f8c76dee05199cd66a64c52aa80351363fc91830a3e7eff500235ff5c69ff02823bc95ac6a89a3fd461e7921c71a8ccb57635f073f3a1b29a71071003fc0be48a5aa8990"}, + {"0xa40a04a2472305ed9478e4c4eb679c1cf87bad62fff861126ad8969c548ffa26543e86f1c1d27957a59aa160465d5ef918cd65e450a2973cd329b5480adf5911a750b83ec47ca6f60866eba9f5cb0f2c11b38e7caa549f970d2a3190a03dca"}, + {"0x1e0f2070926cb9da608e7a9daad66a92ea5236683edecabeb6fa27abf86c91f8007095f818b4581f306698731cda8328dbf7ec5526cd091746e7a9545a34f943ed863ba6982ce022f6f63d9102c7508f332dc3b5de64c22435f0937548c9a2"}, + {"0xc3a32f1093a2d37f26a614efc790a279c8284c321c191637dd146829dc90518ff37b4801cf7688fdbedf8984cd0292c99034198757d5b07e946c0f4aaf869d7613162bdb8c2b9f64e958a97391e099d0f12f032c6458e1213a0a44282225fa"}, + {"0xe02ea67182f3fe3d578b08f0d7928b7c6fdca2115b687ebf858dfa3ed273ed68a9853fa0675254cdbf5e038e2dff11fe6be1ac0acfb7e2d69713c9e5053107232558137964f4d8c75f9d499b5d1172c7c7c7ca17ba1552c181482c6fde568c"}, + {"0xb7bdc820045b8cb4750d2cf14442e75e71ff88850bb68c703a9d570b4ead2265e1433921511be60f0f494ef406d6ffab61439f2492902d06a47ab797611ed56a2db85dbc6ca66ea91fbded330d1607a8f0665333167eac5036e8809c424602"}, + {"0x4b874c4266a94c9645d7235482a22dc864d3a95f9123f6dd42ac37687a32fb96d6d078704623519d355e7d2942b96183761b60a96d86b24158041b2d27e0b6d83f524e2dfd36aa32c722dc52e6c8f90b372e4c69b8d57c400535580e741931"}, + {"0xed7683d3ed7bd7b795127161c1c3d283e2e5264b38ec25fff29cd620f0f35b50bae6134ca7c707fda9f21f1e5ed72dba00b4db93a2289a0ca3325006b7901fd25eb3112b01280113100c8c706e5cf754cfebdadea45bfb1bcad9b55b6a8bec"}, + {"0x798e60091f0baff46af8096d5d385c3ac834078bc68a5a0264b38d84d3e575383492076590dd1c78ce517c938bb2977a4a53c19a224ef3c06480ba9458bc3810382e54b052a61ea2a9eab88b7f2e4379616e835e8aaf9ceb8f7725c00e473b"}, + {"0xe25d6afa99d9845550da2d8be7e54972c881f60e60fc44e1aa4639a469895429c40ded2c5a915747487760917ba655e5bd70e760a60bce724ebe669a6f9a26e612a7e471c491eb901f086651f804b2e8ae65cbc30fbfecc3ab056254152e1e"}, + {"0xd3bd269478c18fe4ae906db51c2c61c8e8eba8c0ffeafee1a4590f0f771c420738c368e903c5bb0ab4ae5d764f1db9d32dd0941af5abdcb799a0a7868ab22b8066bb43409f5618113ee9dbd7095a1132467d7cf792c2edcee3f32fc76e377"}, + {"0x10d8abdaa3480b89ebfe1c4f750c43d1ebec7cfd63adfdcff0904e9b54b762843fc0dd9edb82ce3a6dab718b3805f8bf23d59fe0be8558d3168557f22e481614c83c08a53ef37d647faecda297e45535112f46edc37101ca78aa36db8baa52e"}, + {"0x73757c884a1e868d44f45a39a70be12ca5fbca1045af3c5dfce747238edd7926dc150df6bae0de22fe58a951f68e395e3c6b58285afb6e13d04f58f3be13f468f1d95d89be6973f4af4a03c854d956e4bb87cdb1e85aea019e5f0e2bca4543"}, + {"0x43b12c0a691c949e92b6c9de3f2fd57d511a8f558567437c329ea1602a4f9575c328c6ce9abe3a41d6977eef727257a82e1bbdc6cd86ef0176fbe891af806075e500c1f05f54880ec857442d6fdfe701cfac8e0bfed571913c10eb250e0022"}, + {"0x5dd753e576c5e17fdb31053f4583d11a7efc9842522012c64dcdf4fb1813de9e2342aca1ea200c8e8ea86c846041648ea1ab64d8286960d339fc3605f38472ebd8a8a371d7a6a99360c4a35173bbc8fea0433e13b00707ca26f29726c1201"}, + {"0xf9cb66cab40e4b021cb9ab0d6ecb29134a25c87261d856001610a3d7fcfc485c34c1acb355a69c9fb3e171b3e36814b50b1d58b14f86d2fd7eeed7fd1ab7785800dece186c33a4fab38104a0c5a8abd353622161daf40d37a6d072443c4d84"}, + {"0x11aa8006f5e3cf018df2a06234daddc183d82f632c47e1adfba4c1747e717c7bc6708aef8baaf81d65520bf3eb7543d6ba7267adac6c2b1fdaaada6f47d96485e0ae6a1a959da775932766eb8c044905d42d295e4609c41019d3215a0ecf1ce"}, + {"0x11cebd8fefc74f456542424a4260474172f2ea3de5ae199758cff05a90330816514c564a4ea7b56ff8173a10c9be915b4c4cbc6dacbfde9ae946a963ecfde2fff66ff267019fb3f6bb80f77aaea5a09d18b8fa6f0b9c4f730c41077a869ea60"}, + {"0x43816faa84ded72d8298e803ffd4500b0d6fc6e4fd2febb9f773a0b2b9a7d2d6e2737798e7a85433717d7c3df4cca47295c9763cd9a14a2a5efd2a535d7af007f795da423ddc4709a0fb39ef1159d316b9a072d30a28f62b79383ae61672c"}, + {"0xbd64fcab7189eba72da0f52543636cdf11c17cf200f39297021b4ddd528da640175c9e79cab502feda518f5643053e92672e569935848dde1411b4f9abf62875b4b0dae6f8a249a05f984d8e2cbe7bc8216896251fc9c801d232ee0a6ace1e"}, + {"0x11908b0ee96ce37dfa9655c3cf2417961b6890de361366d3c889cd33cf5d9726801f9db61f7a445bf3d30e5d2632d899a45da474ca5bc5257cdbeaefee742e5549975d293d3a211b0bff06206bd8da0d66a31684300aa30275ec98af2204fe"}, + {"0x7e3dd2299ac6f6c9b0ca812e5250a5a0a9ac696649ea44304efc9eb17873ba05758cc68535699b63a921dca0c065bc0c74f47dcf13eddfa9a49ade0dfcff10a185ad8a1ea9c0546fd04335ed21eb0c32813b8d98d38ac8444619053ab9e9db"}, + {"0xcecbd40f99ea98da90fa06c98dd11219e5e9dda72c183523827b1fc889ab4a306695fe674307047144468aef1f17993762be4b859483db87b27f442bddb107489d094a51ddf3b5dde5499d79a806e31528ecbebc9894584135547e9875dee7"}, + {"0x8fcd9b98a111fb0b88bc45e05c13e919903c015e73e51c79b1d76f351e36c5640624fcde3e60ad3a5949f9a35dae56bcc3a1886854433eeb48c3498b4b32a913b34b78220b02b0a1cbce157f236d37fb69ef96e98f07644e37c9abd1ceea1c"}, + {"0xbc6e2187eb737df544826df89d5279d06046a2b47664dbb87fce1ab6a3f7edba758835bf0810b4ec4237719e7f801e24e64247f3fec548baf27dbfd691eec0e490ac592e1e066480706aae437bd7bb3ee5c982a9c0ca1575b556005bbea58f"}, + {"0x12170c6c8cd5d3a968d03315342c1251b7e384f85fdfa0d3926b793bd740afa3dc0dc8a51eb829450218c01c0ac8b4eb6163ec1132283f4d366dfbc0582225a6b14163a15df63a27a2ffa2a5da74ee5845d71a8346187ca736714ccbd2b00ce"}, + {"0x1d8792a1d4b4411685a26918d785823cc142a0912ee9a8c1981586b35fb2581492b26b7150fdf1899f678b13789c48c28bae260fb93742507d0323f3f2c908a4b089a4e018ed7b351cf17d05cdca5d13c92201596045f7f89bb44c7e42e17f"}, + {"0x1b457948b6d5eab15ce534d9c997bc32978fce85a19025d325c1705231586ff07f2e334ea9bf39f572423f10f0938ddfb7b44ca8dc8d21317f5ab1c66248922f53126875ee0e35c060f413f4376c474938abc5b57a9ce17c15cdac17c7fce1"}, + {"0x509b78d33906267310fb5764df3a83af5e10b24b3d04ff9a64f1e87872403650d8f05e039b0bbfa50ac9a9a496f509541a5d1ae590acd31e0efea18f9f9b0eae82f2214364c91528dd297288a4a3e04cc82aea73b257947cba2d3c027f3b4e"}, + {"0x34c92249a79e2afe89113c83ff829e7376ebd2bd99f61023336e601144565a3060888f77f83071095752205b778702253fa2a187d9cc0f240fa1401be60298736dabcea50ba63065cc6aae3a089c3bb77dbceefc83fc029a2adf90289d5269"}, + {"0x6158d56b2f6902c287d980c970d8aca6f6d10072eb749afaabdd9a9d098bc6e7bcf07bd1bc8958cb79cbf53dcce6eb72bc34a5c2613384bcde79a64b340640e821855e49f71c073c715dd55768fbbb5a27397cf584fa639d927837ba9a52cf"}, + {"0x6e3c4990d0e48167ffd607fe2c5f4d5e22afdbd2c39113dfb8ff2583d930a9bfa6c2074eefb455bb8ee0618600768b2f85e634791a2f6465642268d8f46d3f10a38d980a60d05c71030b500691002cd7cd01a5497eda666bd77bf2498dfdcf"}, + {"0x2b15f6bcfe35e5d93d3c369fa9e283b137865559be088eb6dcc6e73eb50854b68943546f83849a34668275fa3292da90ea6941391738c9abdda4bdee838b80e7959ad5d72b9fafc33bd1526c7c993dadfed5a79b9bb119c277cef9c7a71dc"}, + {"0xdaf7f2929e35d0ba56ce2742d5d9cce74d572dac5882c678bd6b5f39d7c6d74ee3ec0e4c2e052c635a12ca1389bf62b147c6c85df6adba1b2c70ed3c60424c84dc6b5265e11ec4788ae277f04576101c11009182de27a8eb5953c1aab8e1e2"}, + {"0x4a1b0c9af273773fdf3bd29eae337f09acb8e1b10457187a5f7d43450a6de3b93d3cf86a298a6e99030c0cd203113c46a67fc1689dca1cfbbc663899b2ebf8781db80872c647934862ca898a564fa156b58c554786a7712fdea39d78a366fd"}, + {"0xe22946eb7bdbef6cf67b1b30ff0c6ff4a2d3108d338c55bc561b3ab50db2cb0826365f812464f2cdfd2940476d7fb7db692ce19e2f53bd3486412d1258f91ef75cc0a09b3d72955a6e867452e4e7aa2f1c496fec0b41ff2d5df172664683f0"}, + {"0xcaf9adb7a9fe17c553022cb9fa3ed693a6fe017b6c667b9b3fee7f904fe34ea15e1b671bda21c0e3b8bb07f3301bec8986d8ed48b1461666a88d1b1ec3d12a51b07930b81e544907804d14c5ed8834fc6edc7d660254d8491968ce6034642d"}, + {"0xdae7c72155f240753502352e5ef320d206adde735e9fdda0c6cea0bd48acc5eeca42e615e6a79bfe4f57a3c75816ec327b0fe017bdafda135db84ee4a5cadd38b6c3f32216f411f2a69a45daf35d5242c9ea218557aedfc0c241bef5c25d47"}, + {"0xa44e2a4243eb71846e0c033d0b508654b71ddcbf86b859adcfe48fc5330c4226986f8fe2b405a587c37fb51173e2f438759dd8250235b555a7f99915aba1961c0c1e4abaefcc9ba4d88d08254bef4b4ad5efdebb0f15586981614e65f5a262"}, + {"0x11d90321c1a5e68ce6aeb22eb2c666145d256b2541178474d03d8e918d8ad4fb6e584f004810f1d3e5ebf0ae73645bc8851cd382bb88abf2e65019ca263ce9f961956f03db70d927acff8a5ce8918f6ed96762782c5c78ae56ef3741eeec30e"}, + {"0x73067c544d14eb0fbe73111b96dc68c493c312a408bd3138e176ade7405d93b6553004d77e05da6cf32defa9e65e1267ffe94f6d971f8de118e3bc21fa8b59896ba9a3a1494f176e24195c65730b3fb2c3d0d048de7e13cbe64f64cff8a466"}, + {"0xea2438249db0c31564caec1d831128fe9688db01a3e9b017c68f007bf1dc6782d46226efc730bceb0a4b5d6413f7048bc5b704affb912aed0fdb9d26a3d0add40ebe02bf786a38e8e29e88c6143b9eb289b27fba11a6979905a0bae8c272ce"}, + {"0xb8998d5ec7393dedffe4f708881d1cc145104c8485261ab6df727bc0fa4a7b55dea1a7893791a93790e6af9d1bc0bf3ebe5feb40b340e9e89cee859bc443162e3dbdcda09f1680d74700f56f037e4388aa741daee7bbca5ac789d34210b9ac"}, + {"0x9db9607a944de0743644a01a2bbc68dd869d4df41655c78b91678efa6b297efa53ea116f68a0d01b696ba23cccc34a180d0e888c9d0cd6170b21c7cc47e7040193e605122d2487d0960d31f40fa0f9fb1979f3c9f070ae21d4987aa10635e6"}, + {"0x1064c0575f32e8a01dbb0902016549291db671757d01133b941f80b48ffc6cf6e97ca4112be781a452e4bdaf8188c3db4245c089a8cd9a20a9380970a2f583371a03a3306955b512b8c15992c2689ddd948200fefbd9a23b581426419bdd44a"}, + {"0xb38eb53f5c01ec437a38102c26e021ceab2096dbff88cf994a5e676c67b5e9e2aa0b7b8e5fbf481b9ebb1f2e1143c5d2331b4a7307543827f08ac9b085c9f763eace96795934aaececdb8d5667438f023bd0dcc10a1f53751b46aca1e1a0b3"}, + {"0xd3a1a4efb742aa1a15b063d6601a48f9119b6ad86d32432ed0d80e91fdd274b5a2fb4178cdb5cfadfa462775bed589a228c2974d988b40a7856b1e6f5b7a69201c7226f38239c0e4f57729b74a2a35d56876815defeff9019a4aeaec8ace2a"}, + {"0x890f6b8f09c172a9759a98d2992c4ec9a89e19af59dd9aabcd54dbae2c8bec58b63b35d8b2e0434532e8aea16ac6155c20c944777a8ca9003afa8dd3d6d6ba35ba41c8ea40710297a073dbf4f4b7e2828b20eeb168b3ed9513f7359f8fc075"}, + {"0xec2327808b9cd4a32bc9540933cb13b19057ddfb9d0815a9c3570d94158d5ffff7b1a837c905ea8515e45f571e080770a6d574c1735ec3000d79a494dbab3b2e7c463c8f518ab36199573c42837d74f7b42b001d232aa9847548b8d8c2e9c0"}, + {"0x3347dd7683ba2e167d3b718be720970c262bf6aac6783b7c0c56059a2e218e3983530c568d9666b9e7b1bfd947e1e321e1ef041fad5fdd9e7392055a45b9a13accfb5e13fa30a15f00355721459f71856aa768476a8ea9e0b18cade6ab4f49"}, + {"0x64a3e6bd3ee53dcd1ae4764d398d44760b5c5192d0745d71a452accbbfd3f0f9f106f9866b973d599c20c64ec4b9311f4ec1b991ab43b5b23e865875b56926456fe6399c3f69b7cf8d3bbf6254aef3c137e16a22792898bdf6265a4275368"}, + {"0x6e1f826a09b835ff320046e2dcef94cb16de08591139db2b9f7114d380f921d4b3628b658fbc082d086761efcb1fb03ef83a82e0d19ad5cf8c6888661897eff183bd3379aafcd524318a32f1156d16ce876fbe3e7bdb951028489ce89aee8d"}, + }, + }, + }, + }, +} + +var tBW6_761 = TwistedEdwardsCurve{ + Name: BW6_761.Name, + Package: "twistededwards", + EnumID: BW6_761.EnumID, + A: "-1", + D: "79743", + Cofactor: "8", + Order: "32333053251621136751331591711861691692049189094364332567435817881934511297123972799646723302813083835942624121493", + BaseX: "109887223397525145051017418760180386187632078445902299543670312117371514695798874370143656894667315818446285582389", + BaseY: "31146823455109675839494591101665406662142618451815824757336761504421066243585705807124836638254810186490790034654", } func init() { addCurve(&BW6_761) + addTwistedEdwardCurve(&tBW6_761) } diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/curve.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/curve.go index 18c079a90f1..0c55a6a9762 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/curve.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/curve.go @@ -3,7 +3,7 @@ package config import ( "math/big" - "github.com/consensys/gnark-crypto/field" + "github.com/consensys/gnark-crypto/field/generator/config" ) // Curve describes parameters of the curve useful for the template @@ -15,13 +15,29 @@ type Curve struct { FpModulus string FrModulus string - Fp *field.Field - Fr *field.Field + Fp *config.FieldConfig + Fr *config.FieldConfig FpUnusedBits int FpInfo, FrInfo Field G1 Point G2 Point + + HashE1 HashSuite + HashE2 HashSuite +} + +type TwistedEdwardsCurve struct { + Name string + Package string + EnumID string + + A, D, Cofactor, Order, BaseX, BaseY string + + // set if endomorphism + HasEndomorphism bool + Endo0, Endo1 string + Lambda string } type Field struct { @@ -36,18 +52,23 @@ func (c Curve) Equal(other Curve) bool { type Point struct { CoordType string + CoordExtDegree uint8 // value n, such that q = pⁿ + CoordExtRoot int64 // value a, such that the field is Fp[X]/(Xⁿ - a) PointName string - GLV bool // scalar mulitplication using GLV - CofactorCleaning bool // flag telling if the Cofactor cleaning is available - CRange []int // multiexp bucket method: generate inner methods (with const arrays) for each c - Projective bool // generate projective coordinates + GLV bool // scalar multiplication using GLV + CofactorCleaning bool // flag telling if the Cofactor cleaning is available + CRange []int // multiexp bucket method: generate inner methods (with const arrays) for each c + Projective bool // generate projective coordinates + A []string //A linear coefficient in Weierstrass form + B []string //B constant term in Weierstrass form } var Curves []Curve +var TwistedEdwardsCurves []TwistedEdwardsCurve func defaultCRange() []int { // default range for C values in the multiExp - return []int{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22} + return []int{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} } func addCurve(c *Curve) { @@ -57,6 +78,10 @@ func addCurve(c *Curve) { Curves = append(Curves, *c) } +func addTwistedEdwardCurve(c *TwistedEdwardsCurve) { + TwistedEdwardsCurves = append(TwistedEdwardsCurves, *c) +} + func newFieldInfo(modulus string) Field { var F Field var bModulus big.Int @@ -65,7 +90,13 @@ func newFieldInfo(modulus string) Field { } F.Bits = bModulus.BitLen() - F.Bytes = len(bModulus.Bits()) * 8 + F.Bytes = (F.Bits + 7) / 8 F.Modulus = func() *big.Int { return new(big.Int).Set(&bModulus) } return F } + +type FieldDependency struct { + FieldPackagePath string + ElementType string + FieldPackageName string +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/hash_to_curve.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/hash_to_curve.go new file mode 100644 index 00000000000..cb7c5b91429 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/hash_to_curve.go @@ -0,0 +1,202 @@ +package config + +import ( + "math/big" + + field "github.com/consensys/gnark-crypto/field/generator/config" +) + +type FieldElementToCurvePoint string + +const ( + SSWU FieldElementToCurvePoint = "SSWU" + SVDW FieldElementToCurvePoint = "SVDW" +) + +type Isogeny struct { + + //Isogeny to original curve + XMap RationalPolynomial + YMap RationalPolynomial // The y map is also evaluated on x. The result is multiplied by y. +} + +type RationalPolynomial struct { + Num [][]string //Num is stored + Den [][]string //Den is stored. It is also monic. The leading coefficient (1) is omitted. +} + +type HashSuite interface { + GetInfo(baseField *field.FieldConfig, g *Point, name string) HashSuiteInfo +} + +type HashSuiteSswu struct { + //TODO: Move into Isogeny + A []string // A is the Weierstrass curve coefficient of x in the isogenous curve over which the SSWU map is evaluated. + B []string // B is the Weierstrass curve constant term in the isogenous curve over which the SSWU map is evaluated. + + Z []int // z (or zeta) is a quadratic non-residue with //TODO: some extra nice properties, refer to WB19 + Isogeny *Isogeny +} + +func toBigIntSlice(z []int) []big.Int { + res := make([]big.Int, len(z)) + for i := 0; i < len(z); i++ { + res[i].SetInt64(int64(z[i])) + } + return res +} + +type HashSuiteSvdw struct { + z []string + c1 []string + c2 []string + c3 []string + c4 []string +} + +func (parameters *HashSuiteSvdw) GetInfo(baseField *field.FieldConfig, g *Point, name string) HashSuiteInfo { + f := field.NewTower(baseField, g.CoordExtDegree, g.CoordExtRoot) + c := []field.Element{ + field.NewElement(parameters.z), + field.NewElement(parameters.c1), + field.NewElement(parameters.c2), + field.NewElement(parameters.c3), + field.NewElement(parameters.c4), + } + return HashSuiteInfo{ + PrecomputedParams: c, + CofactorClearing: g.CofactorCleaning, + Point: g, + MappingAlgorithm: SVDW, + Name: name, + FieldCoordName: field.CoordNameForExtensionDegree(g.CoordExtDegree), + Field: &f, + } +} + +func (suite *HashSuiteSswu) GetInfo(baseField *field.FieldConfig, g *Point, name string) HashSuiteInfo { + + f := field.NewTower(baseField, g.CoordExtDegree, g.CoordExtRoot) + fieldSizeMod256 := uint8(f.Size.Bits()[0]) + + Z := toBigIntSlice(suite.Z) + var c []field.Element + + if fieldSizeMod256%4 == 3 { + c = make([]field.Element, 2) + c[0] = make([]big.Int, 1) + c[0][0].Rsh(&f.Size, 2) + + c[1] = f.Neg(Z) + c[1] = f.Sqrt(c[1]) + + } else if fieldSizeMod256%8 == 5 { + c = make([]field.Element, 3) + c[0] = make([]big.Int, 1) + c[0][0].Rsh(&f.Size, 3) + + c[1] = make([]big.Int, f.Degree) + c[1][0].SetInt64(-1) + c[1] = f.Sqrt(c[1]) + + c[2] = f.Inverse(c[1]) + c[2] = f.Mul(Z, c[2]) + c[2] = f.Sqrt(c[2]) + + } else if fieldSizeMod256%8 == 1 { + ONE := big.NewInt(1) + c = make([]field.Element, 3) + + c[0] = make([]big.Int, 5) + // c1 .. c5 stored as c[0][0] .. c[0][4] + c[0][0].Sub(&f.Size, big.NewInt(1)) + c1 := c[0][0].TrailingZeroBits() + c[0][0].SetUint64(uint64(c1)) + + var twoPowC1 big.Int + twoPowC1.Lsh(ONE, c1) + c[0][1].Rsh(&f.Size, c1) + c[0][2].Rsh(&c[0][1], 1) + c[0][3].Sub(&twoPowC1, ONE) + c[0][4].Rsh(&twoPowC1, 1) + + // c6, c7 stored as c[1], c[2] respectively + c[1] = f.Exp(Z, &c[0][1]) + + var c7Pow big.Int + c7Pow.Add(&c[0][1], ONE) + c7Pow.Rsh(&c7Pow, 1) + c[2] = f.Exp(Z, &c7Pow) + + } else { + panic("this is logically impossible") + } + + return HashSuiteInfo{ + A: field.NewElement(suite.A), + B: field.NewElement(suite.B), + Z: Z, + Point: g, + CofactorClearing: g.CofactorCleaning, + Name: name, + Isogeny: newIsogenousCurveInfoOptional(suite.Isogeny), + FieldSizeMod256: fieldSizeMod256, + PrecomputedParams: c, + Field: &f, + FieldCoordName: field.CoordNameForExtensionDegree(g.CoordExtDegree), + MappingAlgorithm: SSWU, + } +} + +func stringMatrixToIntMatrix(s [][]string) []field.Element { + res := make([]field.Element, len(s)) + for i, S := range s { + res[i] = field.NewElement(S) + } + return res +} + +func newIsogenousCurveInfoOptional(isogenousCurve *Isogeny) *IsogenyInfo { + if isogenousCurve == nil { + return nil + } + return &IsogenyInfo{ + XMap: RationalPolynomialInfo{ + stringMatrixToIntMatrix(isogenousCurve.XMap.Num), + stringMatrixToIntMatrix(isogenousCurve.XMap.Den), + }, + YMap: RationalPolynomialInfo{ + stringMatrixToIntMatrix(isogenousCurve.YMap.Num), + stringMatrixToIntMatrix(isogenousCurve.YMap.Den), + }, + } +} + +type IsogenyInfo struct { + XMap RationalPolynomialInfo + YMap RationalPolynomialInfo // The y map is also evaluated on x. The result is multiplied by y. +} + +type RationalPolynomialInfo struct { + Num []field.Element + Den []field.Element //denominator is monic. The leading coefficient (1) is omitted. +} + +type HashSuiteInfo struct { + //Isogeny to original curve + Isogeny *IsogenyInfo //pointer so it's nullable. + + A []big.Int //TODO: Move inside IsogenyInfo + B []big.Int + + Point *Point + Field *field.Extension + FieldCoordName string + Name string + FieldSizeMod256 uint8 + PrecomputedParams []field.Element // PrecomputedParams[0][n] correspond to integer cₙ₋₁ in std doc + // PrecomputedParams[n≥1] correspond to field element c_( len(PrecomputedParams[0]) + n - 1 ) in std doc + Z []big.Int // z (or zeta) is a quadratic non-residue with //TODO: some extra nice properties, refer to WB19 + CofactorClearing bool + MappingAlgorithm FieldElementToCurvePoint +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/secp256k1.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/secp256k1.go new file mode 100644 index 00000000000..6c0d6b7d914 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/secp256k1.go @@ -0,0 +1,28 @@ +package config + +var SECP256K1 = Curve{ + Name: "secp256k1", + CurvePackage: "secp256k1", + EnumID: "SECP256k1", + FrModulus: "115792089237316195423570985008687907852837564279074904382605163141518161494337", + FpModulus: "115792089237316195423570985008687907853269984665640564039457584007908834671663", + G1: Point{ + CoordType: "fp.Element", + CoordExtDegree: 1, + PointName: "g1", + GLV: true, + CofactorCleaning: false, + CRange: []int{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + }, + HashE1: &HashSuiteSvdw{ + z: []string{"1"}, + c1: []string{"8"}, + c2: []string{"57896044618658097711785492504343953926634992332820282019728792003954417335831"}, + c3: []string{"10388779673325959979325452626823788324994718367665745800388075445979975427086"}, + c4: []string{"77194726158210796949047323339125271902179989777093709359638389338605889781098"}, + }, +} + +func init() { + addCurve(&SECP256K1) +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/generator/config/stark-curve.go b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/stark-curve.go new file mode 100644 index 00000000000..34c267d8b10 --- /dev/null +++ b/vendor/github.com/consensys/gnark-crypto/internal/generator/config/stark-curve.go @@ -0,0 +1,28 @@ +package config + +var STARK_CURVE = Curve{ + Name: "stark-curve", + CurvePackage: "starkcurve", + EnumID: "STARK_CURVE", + FrModulus: "3618502788666131213697322783095070105526743751716087489154079457884512865583", + FpModulus: "3618502788666131213697322783095070105623107215331596699973092056135872020481", + G1: Point{ + CoordType: "fp.Element", + CoordExtDegree: 1, + PointName: "g1", + GLV: false, + CofactorCleaning: false, + CRange: defaultCRange(), + }, + HashE1: &HashSuiteSvdw{ + z: []string{"1"}, + c1: []string{"3141592653589793238462643383279502884197169399375105820974944592307816406667"}, + c2: []string{"1809251394333065606848661391547535052811553607665798349986546028067936010240"}, + c3: []string{"747120397548504753672821049844706693752799645928246271384591722031176001048"}, + c4: []string{"272520077186478842991245371323181269386250180546566216570369979330317493608"}, + }, +} + +func init() { + addCurve(&STARK_CURVE) +} diff --git a/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go b/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go index 803de3c1b1d..05f9a8f666b 100644 --- a/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go +++ b/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go @@ -11,7 +11,19 @@ func Execute(nbIterations int, work func(int, int), maxCpus ...int) { nbTasks := runtime.NumCPU() if len(maxCpus) == 1 { nbTasks = maxCpus[0] + if nbTasks < 1 { + nbTasks = 1 + } else if nbTasks > 512 { + nbTasks = 512 + } + } + + if nbTasks == 1 { + // no go routines + work(0, nbIterations) + return } + nbIterationsPerCpus := nbIterations / nbTasks // more CPUs than tasks: a CPU will work on exactly one iteration diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH.go index af6de9a895d..45f23762a82 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH_32.go new file mode 100644 index 00000000000..a1fdf8fff92 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ARCH_32.go @@ -0,0 +1,29 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* AMCL BIG number class */ + +package FP256BN + +type Chunk int32 +type DChunk int64 + +const CHUNK int = 32 /* Set word size */ diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG.go index 850a27af249..ef05d19e2c3 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -21,10 +23,11 @@ under the License. package FP256BN -import "strconv" -import "github.com/hyperledger/fabric-amcl/amcl" - +import ( + "strconv" + "github.com/hyperledger/fabric-amcl/amcl" +) //const MODBYTES uint = @NB@ //const BASEBITS uint = @BASE@ @@ -782,7 +785,9 @@ func (r *BIG) Jacobi(p *BIG) int { /* this=1/this mod p. Binary method */ func (r *BIG) Invmodp(p *BIG) { r.Mod(p) - if r.iszilch() {return} + if r.iszilch() { + return + } u := NewBIGcopy(r) v := NewBIGcopy(p) diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG_32.go new file mode 100644 index 00000000000..802f0a21be4 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BIG_32.go @@ -0,0 +1,991 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* AMCL BIG number class */ + +package FP256BN + +import "strconv" +import "github.com/hyperledger/fabric-amcl/amcl" + +//const MODBYTES uint = @NB@ +//const BASEBITS uint = @BASE@ + +//const NLEN int = int((1 + ((8*MODBYTES - 1) / BASEBITS))) +//const DNLEN int = 2 * NLEN +//const BMASK Chunk = ((Chunk(1) << BASEBITS) - 1) +//const HBITS uint = (BASEBITS / 2) +//const HMASK Chunk = ((Chunk(1) << HBITS) - 1) +//const NEXCESS int = (1 << (uint(CHUNK) - BASEBITS - 1)) + +//const BIGBITS int = int(MODBYTES * 8) + +type BIG struct { + w [NLEN]Chunk +} + +type DBIG struct { + w [2 * NLEN]Chunk +} + +/***************** 32-bit specific code ****************/ + +/* First the 32/64-bit dependent BIG code */ +/* Note that because of the lack of a 128-bit integer, 32 and 64-bit code needs to be done differently */ + +/* return a*b as DBIG */ +func mul(a *BIG, b *BIG) *DBIG { + c := NewDBIG() + var d [NLEN]DChunk + + for i := 0; i < NLEN; i++ { + d[i] = DChunk(a.w[i]) * DChunk(b.w[i]) + } + s := d[0] + t := s + c.w[0] = Chunk(t) & BMASK + co := t >> BASEBITS + + for k := 1; k < NLEN; k++ { + s += d[k] + t = co + s + for i := k; i >= 1+k/2; i-- { + t += DChunk(a.w[i]-a.w[k-i]) * DChunk(b.w[k-i]-b.w[i]) + } + c.w[k] = Chunk(t) & BMASK + co = t >> BASEBITS + } + + for k := NLEN; k < 2*NLEN-1; k++ { + s -= d[k-NLEN] + t = co + s + for i := NLEN - 1; i >= 1+k/2; i-- { + t += DChunk(a.w[i]-a.w[k-i]) * DChunk(b.w[k-i]-b.w[i]) + } + c.w[k] = Chunk(t) & BMASK + co = t >> BASEBITS + } + c.w[2*NLEN-1] = Chunk(co) + + return c +} + +/* return a^2 as DBIG */ +func sqr(a *BIG) *DBIG { + c := NewDBIG() + + t := DChunk(a.w[0]) * DChunk(a.w[0]) + c.w[0] = Chunk(t) & BMASK + co := t >> BASEBITS + + for j := 1; j < NLEN-1; { + t = DChunk(a.w[j]) * DChunk(a.w[0]) + for i := 1; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + t = DChunk(a.w[j]) * DChunk(a.w[0]) + for i := 1; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + t += DChunk(a.w[j/2]) * DChunk(a.w[j/2]) + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + } + + for j := NLEN - 1 + (NLEN % 2); j < DNLEN-3; { + t = DChunk(a.w[NLEN-1]) * DChunk(a.w[j-NLEN+1]) + for i := j - NLEN + 2; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + t = DChunk(a.w[NLEN-1]) * DChunk(a.w[j-NLEN+1]) + for i := j - NLEN + 2; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + t += DChunk(a.w[j/2]) * DChunk(a.w[j/2]) + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + } + + t = DChunk(a.w[NLEN-2]) * DChunk(a.w[NLEN-1]) + t += t + t += co + c.w[DNLEN-3] = Chunk(t) & BMASK + co = t >> BASEBITS + + t = DChunk(a.w[NLEN-1])*DChunk(a.w[NLEN-1]) + co + c.w[DNLEN-2] = Chunk(t) & BMASK + co = t >> BASEBITS + c.w[DNLEN-1] = Chunk(co) + + return c +} + +func monty(m *BIG, mc Chunk, d *DBIG) *BIG { + var dd [NLEN]DChunk + + var v [NLEN]Chunk + b := NewBIG() + + t := DChunk(d.w[0]) + v[0] = (Chunk(t) * mc) & BMASK + t += DChunk(v[0]) * DChunk(m.w[0]) + c := (t >> BASEBITS) + DChunk(d.w[1]) + s := DChunk(0) + + for k := 1; k < NLEN; k++ { + t = c + s + DChunk(v[0])*DChunk(m.w[k]) + for i := k - 1; i > k/2; i-- { + t += DChunk(v[k-i]-v[i]) * DChunk(m.w[i]-m.w[k-i]) + } + v[k] = (Chunk(t) * mc) & BMASK + t += DChunk(v[k]) * DChunk(m.w[0]) + c = (t >> BASEBITS) + DChunk(d.w[k+1]) + dd[k] = DChunk(v[k]) * DChunk(m.w[k]) + s += dd[k] + } + for k := NLEN; k < 2*NLEN-1; k++ { + t = c + s + for i := NLEN - 1; i >= 1+k/2; i-- { + t += DChunk(v[k-i]-v[i]) * DChunk(m.w[i]-m.w[k-i]) + } + b.w[k-NLEN] = Chunk(t) & BMASK + c = (t >> BASEBITS) + DChunk(d.w[k+1]) + s -= dd[k-NLEN+1] + } + b.w[NLEN-1] = Chunk(c) & BMASK + return b +} + +/* set this[i]+=x*y+c, and return high part */ +func muladd(a Chunk, b Chunk, c Chunk, r Chunk) (Chunk, Chunk) { + var prod = DChunk(a)*DChunk(b) + DChunk(c) + DChunk(r) + bot := Chunk(prod) & BMASK + top := Chunk(prod >> BASEBITS) + return top, bot +} + +/***************************************************************************/ + +func (r *BIG) get(i int) Chunk { + return r.w[i] +} + +func (r *BIG) set(i int, x Chunk) { + r.w[i] = x +} + +func (r *BIG) xortop(x Chunk) { + r.w[NLEN-1] ^= x +} + +/* normalise BIG - force all digits < 2^BASEBITS */ +func (r *BIG) norm() Chunk { + carry := Chunk(0) + for i := 0; i < NLEN-1; i++ { + d := r.w[i] + carry + r.w[i] = d & BMASK + carry = d >> BASEBITS + } + r.w[NLEN-1] = (r.w[NLEN-1] + carry) + return (r.w[NLEN-1] >> ((8 * MODBYTES) % BASEBITS)) +} + +/* Shift right by less than a word */ +func (r *BIG) fshr(k uint) int { + w := r.w[0] & ((Chunk(1) << k) - 1) /* shifted out part */ + for i := 0; i < NLEN-1; i++ { + r.w[i] = (r.w[i] >> k) | ((r.w[i+1] << (BASEBITS - k)) & BMASK) + } + r.w[NLEN-1] = r.w[NLEN-1] >> k + return int(w) +} + +/* Shift right by less than a word */ +func (r *BIG) fshl(k uint) int { + r.w[NLEN-1] = (r.w[NLEN-1] << k) | (r.w[NLEN-2] >> (BASEBITS - k)) + for i := NLEN - 2; i > 0; i-- { + r.w[i] = ((r.w[i] << k) & BMASK) | (r.w[i-1] >> (BASEBITS - k)) + } + r.w[0] = (r.w[0] << k) & BMASK + return int(r.w[NLEN-1] >> ((8 * MODBYTES) % BASEBITS)) /* return excess - only used in ff.c */ +} + +func NewBIG() *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = 0 + } + return b +} + +func NewBIGints(x [NLEN]Chunk) *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = x[i] + } + return b +} + +func NewBIGint(x int) *BIG { + b := new(BIG) + b.w[0] = Chunk(x) + for i := 1; i < NLEN; i++ { + b.w[i] = 0 + } + return b +} + +func NewBIGcopy(x *BIG) *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = x.w[i] + } + return b +} + +func NewBIGdcopy(x *DBIG) *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = x.w[i] + } + return b +} + +/* test for zero */ +func (r *BIG) iszilch() bool { + for i := 0; i < NLEN; i++ { + if r.w[i] != 0 { + return false + } + } + return true +} + +/* set to zero */ +func (r *BIG) zero() { + for i := 0; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* Test for equal to one */ +func (r *BIG) isunity() bool { + for i := 1; i < NLEN; i++ { + if r.w[i] != 0 { + return false + } + } + if r.w[0] != 1 { + return false + } + return true +} + +/* set to one */ +func (r *BIG) one() { + r.w[0] = 1 + for i := 1; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* Copy from another BIG */ +func (r *BIG) copy(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = x.w[i] + } +} + +/* Copy from another DBIG */ +func (r *BIG) dcopy(x *DBIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = x.w[i] + } +} + +/* Conditional swap of two bigs depending on d using XOR - no branches */ +func (r *BIG) cswap(b *BIG, d int) { + c := Chunk(d) + c = ^(c - 1) + + for i := 0; i < NLEN; i++ { + t := c & (r.w[i] ^ b.w[i]) + r.w[i] ^= t + b.w[i] ^= t + } +} + +func (r *BIG) cmove(g *BIG, d int) { + b := Chunk(-d) + + for i := 0; i < NLEN; i++ { + r.w[i] ^= (r.w[i] ^ g.w[i]) & b + } +} + +/* general shift right */ +func (r *BIG) shr(k uint) { + n := (k % BASEBITS) + m := int(k / BASEBITS) + for i := 0; i < NLEN-m-1; i++ { + r.w[i] = (r.w[m+i] >> n) | ((r.w[m+i+1] << (BASEBITS - n)) & BMASK) + } + r.w[NLEN-m-1] = r.w[NLEN-1] >> n + for i := NLEN - m; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* general shift left */ +func (r *BIG) shl(k uint) { + n := k % BASEBITS + m := int(k / BASEBITS) + + r.w[NLEN-1] = (r.w[NLEN-1-m] << n) + if NLEN >= m+2 { + r.w[NLEN-1] |= (r.w[NLEN-m-2] >> (BASEBITS - n)) + } + for i := NLEN - 2; i > m; i-- { + r.w[i] = ((r.w[i-m] << n) & BMASK) | (r.w[i-m-1] >> (BASEBITS - n)) + } + r.w[m] = (r.w[0] << n) & BMASK + for i := 0; i < m; i++ { + r.w[i] = 0 + } +} + +/* return number of bits */ +func (r *BIG) nbits() int { + t := NewBIGcopy(r) + k := NLEN - 1 + t.norm() + for k >= 0 && t.w[k] == 0 { + k-- + } + if k < 0 { + return 0 + } + bts := int(BASEBITS) * k + c := t.w[k] + for c != 0 { + c /= 2 + bts++ + } + return bts +} + +/* Convert to Hex String */ +func (r *BIG) ToString() string { + s := "" + len := r.nbits() + + if len%4 == 0 { + len /= 4 + } else { + len /= 4 + len++ + + } + MB := int(MODBYTES * 2) + if len < MB { + len = MB + } + + for i := len - 1; i >= 0; i-- { + b := NewBIGcopy(r) + + b.shr(uint(i * 4)) + s += strconv.FormatInt(int64(b.w[0]&15), 16) + } + return s +} + +func (r *BIG) add(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = r.w[i] + x.w[i] + } +} + +func (r *BIG) or(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = r.w[i] | x.w[i] + } +} + +/* return this+x */ +func (r *BIG) Plus(x *BIG) *BIG { + s := new(BIG) + for i := 0; i < NLEN; i++ { + s.w[i] = r.w[i] + x.w[i] + } + return s +} + +/* this+=x, where x is int */ +func (r *BIG) inc(x int) { + r.norm() + r.w[0] += Chunk(x) +} + +/* this*=c and catch overflow in DBIG */ +func (r *BIG) pxmul(c int) *DBIG { + m := NewDBIG() + carry := Chunk(0) + for j := 0; j < NLEN; j++ { + carry, m.w[j] = muladd(r.w[j], Chunk(c), carry, m.w[j]) + } + m.w[NLEN] = carry + return m +} + +/* return this-x */ +func (r *BIG) Minus(x *BIG) *BIG { + d := new(BIG) + for i := 0; i < NLEN; i++ { + d.w[i] = r.w[i] - x.w[i] + } + return d +} + +/* this-=x */ +func (r *BIG) sub(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = r.w[i] - x.w[i] + } +} + +/* reverse subtract this=x-this */ +func (r *BIG) rsub(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = x.w[i] - r.w[i] + } +} + +/* this-=x, where x is int */ +func (r *BIG) dec(x int) { + r.norm() + r.w[0] -= Chunk(x) +} + +/* this*=x, where x is small intNEXCESS */ +func (r *BIG) pmul(c int) Chunk { + carry := Chunk(0) + // r.norm(); + for i := 0; i < NLEN; i++ { + ak := r.w[i] + r.w[i] = 0 + carry, r.w[i] = muladd(ak, Chunk(c), carry, r.w[i]) + } + return carry +} + +/* convert this BIG to byte array */ +func (r *BIG) tobytearray(b []byte, n int) { + //r.norm(); + c := NewBIGcopy(r) + c.norm() + for i := int(MODBYTES) - 1; i >= 0; i-- { + b[i+n] = byte(c.w[0]) + c.fshr(8) + } +} + +/* convert from byte array to BIG */ +func frombytearray(b []byte, n int) *BIG { + m := NewBIG() + for i := 0; i < int(MODBYTES); i++ { + m.fshl(8) + m.w[0] += Chunk(int(b[i+n] & 0xff)) + } + return m +} + +func (r *BIG) ToBytes(b []byte) { + r.tobytearray(b, 0) +} + +func FromBytes(b []byte) *BIG { + return frombytearray(b, 0) +} + +/* divide by 3 */ +func (r *BIG) div3() int { + carry := Chunk(0) + r.norm() + base := (Chunk(1) << BASEBITS) + for i := NLEN - 1; i >= 0; i-- { + ak := (carry*base + r.w[i]) + r.w[i] = ak / 3 + carry = ak % 3 + } + return int(carry) +} + +/* return a*b where result fits in a BIG */ +func smul(a *BIG, b *BIG) *BIG { + carry := Chunk(0) + c := NewBIG() + for i := 0; i < NLEN; i++ { + carry = 0 + for j := 0; j < NLEN; j++ { + if i+j < NLEN { + carry, c.w[i+j] = muladd(a.w[i], b.w[j], carry, c.w[i+j]) + } + } + } + return c +} + +/* Compare a and b, return 0 if a==b, -1 if ab. Inputs must be normalised */ +func Comp(a *BIG, b *BIG) int { + for i := NLEN - 1; i >= 0; i-- { + if a.w[i] == b.w[i] { + continue + } + if a.w[i] > b.w[i] { + return 1 + } else { + return -1 + } + } + return 0 +} + +/* return parity */ +func (r *BIG) parity() int { + return int(r.w[0] % 2) +} + +/* return n-th bit */ +func (r *BIG) bit(n int) int { + if (r.w[n/int(BASEBITS)] & (Chunk(1) << (uint(n) % BASEBITS))) > 0 { + return 1 + } + return 0 +} + +/* return n last bits */ +func (r *BIG) lastbits(n int) int { + msk := (1 << uint(n)) - 1 + r.norm() + return (int(r.w[0])) & msk +} + +/* set x = x mod 2^m */ +func (r *BIG) mod2m(m uint) { + wd := int(m / BASEBITS) + bt := m % BASEBITS + msk := (Chunk(1) << bt) - 1 + r.w[wd] &= msk + for i := wd + 1; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* a=1/a mod 2^256. This is very fast! */ +func (r *BIG) invmod2m() { + U := NewBIG() + b := NewBIG() + c := NewBIG() + + U.inc(invmod256(r.lastbits(8))) + + for i := 8; i < BIGBITS; i <<= 1 { + U.norm() + ui := uint(i) + b.copy(r) + b.mod2m(ui) + t1 := smul(U, b) + t1.shr(ui) + c.copy(r) + c.shr(ui) + c.mod2m(ui) + + t2 := smul(U, c) + t2.mod2m(ui) + t1.add(t2) + t1.norm() + b = smul(t1, U) + t1.copy(b) + t1.mod2m(ui) + + t2.one() + t2.shl(ui) + t1.rsub(t2) + t1.norm() + t1.shl(ui) + U.add(t1) + } + U.mod2m(8 * MODBYTES) + r.copy(U) + r.norm() +} + +/* reduce this mod m */ +func (r *BIG) Mod(m1 *BIG) { + m := NewBIGcopy(m1) + sr := NewBIG() + r.norm() + if Comp(r, m) < 0 { + return + } + + m.fshl(1) + k := 1 + + for Comp(r, m) >= 0 { + m.fshl(1) + k++ + } + + for k > 0 { + m.fshr(1) + + sr.copy(r) + sr.sub(m) + sr.norm() + r.cmove(sr, int(1-((sr.w[NLEN-1]>>uint(CHUNK-1))&1))) + k-- + } +} + +/* divide this by m */ +func (r *BIG) div(m1 *BIG) { + m := NewBIGcopy(m1) + var d int + k := 0 + r.norm() + sr := NewBIG() + e := NewBIGint(1) + b := NewBIGcopy(r) + r.zero() + + for Comp(b, m) >= 0 { + e.fshl(1) + m.fshl(1) + k++ + } + + for k > 0 { + m.fshr(1) + e.fshr(1) + + sr.copy(b) + sr.sub(m) + sr.norm() + d = int(1 - ((sr.w[NLEN-1] >> uint(CHUNK-1)) & 1)) + b.cmove(sr, d) + sr.copy(r) + sr.add(e) + sr.norm() + r.cmove(sr, d) + k-- + } +} + +/* get 8*MODBYTES size random number */ +func random(rng *amcl.RAND) *BIG { + m := NewBIG() + var j int = 0 + var r byte = 0 + /* generate random BIG */ + for i := 0; i < 8*int(MODBYTES); i++ { + if j == 0 { + r = rng.GetByte() + } else { + r >>= 1 + } + + b := Chunk(int(r & 1)) + m.shl(1) + m.w[0] += b + j++ + j &= 7 + } + return m +} + +/* Create random BIG in portable way, one bit at a time */ +func Randomnum(q *BIG, rng *amcl.RAND) *BIG { + d := NewDBIG() + var j int = 0 + var r byte = 0 + for i := 0; i < 2*q.nbits(); i++ { + if j == 0 { + r = rng.GetByte() + } else { + r >>= 1 + } + + b := Chunk(int(r & 1)) + d.shl(1) + d.w[0] += b + j++ + j &= 7 + } + m := d.mod(q) + return m +} + +/* return a*b mod m */ +func Modmul(a1, b1, m *BIG) *BIG { + a := NewBIGcopy(a1) + b := NewBIGcopy(b1) + a.Mod(m) + b.Mod(m) + d := mul(a, b) + return d.mod(m) +} + +/* return a^2 mod m */ +func Modsqr(a1, m *BIG) *BIG { + a := NewBIGcopy(a1) + a.Mod(m) + d := sqr(a) + return d.mod(m) +} + +/* return -a mod m */ +func Modneg(a1, m *BIG) *BIG { + a := NewBIGcopy(a1) + a.Mod(m) + return m.Minus(a) +} + +/* Jacobi Symbol (this/p). Returns 0, 1 or -1 */ +func (r *BIG) Jacobi(p *BIG) int { + m := 0 + t := NewBIGint(0) + x := NewBIGint(0) + n := NewBIGint(0) + zilch := NewBIGint(0) + one := NewBIGint(1) + if p.parity() == 0 || Comp(r, zilch) == 0 || Comp(p, one) <= 0 { + return 0 + } + r.norm() + x.copy(r) + n.copy(p) + x.Mod(p) + + for Comp(n, one) > 0 { + if Comp(x, zilch) == 0 { + return 0 + } + n8 := n.lastbits(3) + k := 0 + for x.parity() == 0 { + k++ + x.shr(1) + } + if k%2 == 1 { + m += (n8*n8 - 1) / 8 + } + m += (n8 - 1) * (x.lastbits(2) - 1) / 4 + t.copy(n) + t.Mod(x) + n.copy(x) + x.copy(t) + m %= 2 + + } + if m == 0 { + return 1 + } + return -1 +} + +/* this=1/this mod p. Binary method */ +func (r *BIG) Invmodp(p *BIG) { + r.Mod(p) + if r.iszilch() { + return + } + u := NewBIGcopy(r) + + v := NewBIGcopy(p) + x1 := NewBIGint(1) + x2 := NewBIGint(0) + t := NewBIGint(0) + one := NewBIGint(1) + for Comp(u, one) != 0 && Comp(v, one) != 0 { + for u.parity() == 0 { + u.fshr(1) + if x1.parity() != 0 { + x1.add(p) + x1.norm() + } + x1.fshr(1) + } + for v.parity() == 0 { + v.fshr(1) + if x2.parity() != 0 { + x2.add(p) + x2.norm() + } + x2.fshr(1) + } + if Comp(u, v) >= 0 { + u.sub(v) + u.norm() + if Comp(x1, x2) >= 0 { + x1.sub(x2) + } else { + t.copy(p) + t.sub(x2) + x1.add(t) + } + x1.norm() + } else { + v.sub(u) + v.norm() + if Comp(x2, x1) >= 0 { + x2.sub(x1) + } else { + t.copy(p) + t.sub(x1) + x2.add(t) + } + x2.norm() + } + } + if Comp(u, one) == 0 { + r.copy(x1) + } else { + r.copy(x2) + } +} + +/* return this^e mod m */ +func (r *BIG) Powmod(e1 *BIG, m *BIG) *BIG { + e := NewBIGcopy(e1) + r.norm() + e.norm() + a := NewBIGint(1) + z := NewBIGcopy(e) + s := NewBIGcopy(r) + for true { + bt := z.parity() + z.fshr(1) + if bt == 1 { + a = Modmul(a, s, m) + } + if z.iszilch() { + break + } + s = Modsqr(s, m) + } + return a +} + +/* Arazi and Qi inversion mod 256 */ +func invmod256(a int) int { + var t1 int = 0 + c := (a >> 1) & 1 + t1 += c + t1 &= 1 + t1 = 2 - t1 + t1 <<= 1 + U := t1 + 1 + + // i=2 + b := a & 3 + t1 = U * b + t1 >>= 2 + c = (a >> 2) & 3 + t2 := (U * c) & 3 + t1 += t2 + t1 *= U + t1 &= 3 + t1 = 4 - t1 + t1 <<= 2 + U += t1 + + // i=4 + b = a & 15 + t1 = U * b + t1 >>= 4 + c = (a >> 4) & 15 + t2 = (U * c) & 15 + t1 += t2 + t1 *= U + t1 &= 15 + t1 = 16 - t1 + t1 <<= 4 + U += t1 + + return U +} + +func logb2(w uint32) uint { + v := w + v |= (v >> 1) + v |= (v >> 2) + v |= (v >> 4) + v |= (v >> 8) + v |= (v >> 16) + + v = v - ((v >> 1) & 0x55555555) + v = (v & 0x33333333) + ((v >> 2) & 0x33333333) + r := uint((((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24) + return (r) +} + +// Optimized combined shift, subtract and norm +func ssn(r *BIG, a *BIG, m *BIG) int { + n := NLEN - 1 + m.w[0] = (m.w[0] >> 1) | ((m.w[1] << (BASEBITS - 1)) & BMASK) + r.w[0] = a.w[0] - m.w[0] + carry := r.w[0] >> BASEBITS + r.w[0] &= BMASK + for i := 1; i < n; i++ { + m.w[i] = (m.w[i] >> 1) | ((m.w[i+1] << (BASEBITS - 1)) & BMASK) + r.w[i] = a.w[i] - m.w[i] + carry + carry = r.w[i] >> BASEBITS + r.w[i] &= BMASK + } + m.w[n] >>= 1 + r.w[n] = a.w[n] - m.w[n] + carry + return int((r.w[n] >> uint(CHUNK-1)) & 1) +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS.go index 6163bd9325d..67da081f01d 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -23,8 +25,6 @@ package FP256BN import "github.com/hyperledger/fabric-amcl/amcl" - - const BFS int = int(MODBYTES) const BGS int = int(MODBYTES) const BLS_OK int = 0 diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS_32.go new file mode 100644 index 00000000000..841dd987c6e --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/BLS_32.go @@ -0,0 +1,93 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* Boneh-Lynn-Shacham API Functions */ + +package FP256BN + +import "github.com/hyperledger/fabric-amcl/amcl" + +const BFS int = int(MODBYTES) +const BGS int = int(MODBYTES) +const BLS_OK int = 0 +const BLS_FAIL int = -1 + +/* hash a message to an ECP point, using SHA3 */ + +func Bls_hash(m string) *ECP { + sh := amcl.NewSHA3(amcl.SHA3_SHAKE256) + var hm [BFS]byte + t := []byte(m) + for i := 0; i < len(t); i++ { + sh.Process(t[i]) + } + sh.Shake(hm[:], BFS) + P := ECP_mapit(hm[:]) + return P +} + +/* generate key pair, private key S, public key W */ + +func KeyPairGenerate(rng *amcl.RAND, S []byte, W []byte) int { + G := ECP2_generator() + q := NewBIGints(CURVE_Order) + s := Randomnum(q, rng) + s.ToBytes(S) + G = G2mul(G, s) + G.ToBytes(W) + return BLS_OK +} + +/* Sign message m using private key S to produce signature SIG */ + +func Sign(SIG []byte, m string, S []byte) int { + D := Bls_hash(m) + s := FromBytes(S) + D = G1mul(D, s) + D.ToBytes(SIG, true) + return BLS_OK +} + +/* Verify signature given message m, the signature SIG, and the public key W */ + +func Verify(SIG []byte, m string, W []byte) int { + HM := Bls_hash(m) + D := ECP_fromBytes(SIG) + G := ECP2_generator() + PK := ECP2_fromBytes(W) + D.neg() + + // Use new multi-pairing mechanism + r := initmp() + another(r, G, D) + another(r, PK, HM) + v := miller(r) + + //.. or alternatively + // v := Ate2(G, D, PK, HM) + + v = Fexp(v) + if v.Isunity() { + return BLS_OK + } else { + return BLS_FAIL + } +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG.go index 0b165aee173..72fc04abcc1 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + package FP256BN // BIG length in bytes and number base @@ -13,4 +15,3 @@ const HMASK Chunk = ((Chunk(1) << HBITS) - 1) const NEXCESS int = (1 << (uint(CHUNK) - BASEBITS - 1)) const BIGBITS int = int(MODBYTES * 8) - diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG_32.go new file mode 100644 index 00000000000..d074058b254 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_BIG_32.go @@ -0,0 +1,17 @@ +//go:build 386 || arm + +package FP256BN + +// BIG length in bytes and number base +const MODBYTES uint = 32 +const BASEBITS uint = 28 + +// BIG lengths and Masks +const NLEN int = int((1 + ((8*MODBYTES - 1) / BASEBITS))) +const DNLEN int = 2 * NLEN +const BMASK Chunk = ((Chunk(1) << BASEBITS) - 1) +const HBITS uint = (BASEBITS / 2) +const HMASK Chunk = ((Chunk(1) << HBITS) - 1) +const NEXCESS int = (1 << (uint(CHUNK) - BASEBITS - 1)) + +const BIGBITS int = int(MODBYTES * 8) diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD.go index adfe1983488..204eb103b7a 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD.go @@ -1,3 +1,4 @@ +//go:build !386 && !arm package FP256BN @@ -8,13 +9,12 @@ const MONTGOMERY_FRIENDLY int = 2 const GENERALISED_MERSENNE int = 3 // Modulus details -const MODBITS uint = 256 /* Number of bits in Modulus */ -const MOD8 uint = 3 /* Modulus mod 8 */ +const MODBITS uint = 256 /* Number of bits in Modulus */ +const MOD8 uint = 3 /* Modulus mod 8 */ const MODTYPE int = NOT_SPECIAL //NOT_SPECIAL -const FEXCESS int32=((int32(1)<<24)-1) +const FEXCESS int32 = ((int32(1) << 24) - 1) // Modulus Masks const OMASK Chunk = ((Chunk(-1)) << (MODBITS % BASEBITS)) const TBITS uint = MODBITS % BASEBITS // Number of active bits in top word const TMASK Chunk = (Chunk(1) << TBITS) - 1 - diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD_32.go new file mode 100644 index 00000000000..3813a1018a2 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/CONFIG_FIELD_32.go @@ -0,0 +1,20 @@ +//go:build 386 || arm + +package FP256BN + +// Modulus types +const NOT_SPECIAL int = 0 +const PSEUDO_MERSENNE int = 1 +const MONTGOMERY_FRIENDLY int = 2 +const GENERALISED_MERSENNE int = 3 + +// Modulus details +const MODBITS uint = 256 /* Number of bits in Modulus */ +const MOD8 uint = 3 /* Modulus mod 8 */ +const MODTYPE int = NOT_SPECIAL //NOT_SPECIAL +const FEXCESS int32 = ((int32(1) << 14) - 1) + +// Modulus Masks +const OMASK Chunk = ((Chunk(-1)) << (MODBITS % BASEBITS)) +const TBITS uint = MODBITS % BASEBITS // Number of active bits in top word +const TMASK Chunk = (Chunk(1) << TBITS) - 1 diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG.go index 265a8f28888..61950c84108 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -23,8 +25,6 @@ package FP256BN import "strconv" - - func NewDBIG() *DBIG { b := new(DBIG) for i := 0; i < DNLEN; i++ { diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG_32.go new file mode 100644 index 00000000000..ae7d079d11a --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/DBIG_32.go @@ -0,0 +1,289 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* MiotCL double length DBIG number class */ + +package FP256BN + +import "strconv" + +func NewDBIG() *DBIG { + b := new(DBIG) + for i := 0; i < DNLEN; i++ { + b.w[i] = 0 + } + return b +} + +func NewDBIGcopy(x *DBIG) *DBIG { + b := new(DBIG) + for i := 0; i < DNLEN; i++ { + b.w[i] = x.w[i] + } + return b +} + +func NewDBIGscopy(x *BIG) *DBIG { + b := new(DBIG) + for i := 0; i < NLEN-1; i++ { + b.w[i] = x.w[i] + } + b.w[NLEN-1] = x.get(NLEN-1) & BMASK /* top word normalized */ + b.w[NLEN] = x.get(NLEN-1) >> BASEBITS + + for i := NLEN + 1; i < DNLEN; i++ { + b.w[i] = 0 + } + return b +} + +/* normalise this */ +func (r *DBIG) norm() { + carry := Chunk(0) + for i := 0; i < DNLEN-1; i++ { + d := r.w[i] + carry + r.w[i] = d & BMASK + carry = d >> BASEBITS + } + r.w[DNLEN-1] = (r.w[DNLEN-1] + carry) +} + +/* split DBIG at position n, return higher half, keep lower half */ +func (r *DBIG) split(n uint) *BIG { + t := NewBIG() + m := n % BASEBITS + carry := r.w[DNLEN-1] << (BASEBITS - m) + + for i := DNLEN - 2; i >= NLEN-1; i-- { + nw := (r.w[i] >> m) | carry + carry = (r.w[i] << (BASEBITS - m)) & BMASK + t.set(i-NLEN+1, nw) + } + r.w[NLEN-1] &= ((Chunk(1) << m) - 1) + return t +} + +func (r *DBIG) cmove(g *DBIG, d int) { + var b = Chunk(-d) + + for i := 0; i < DNLEN; i++ { + r.w[i] ^= (r.w[i] ^ g.w[i]) & b + } +} + +/* Compare a and b, return 0 if a==b, -1 if ab. Inputs must be normalised */ +func dcomp(a *DBIG, b *DBIG) int { + for i := DNLEN - 1; i >= 0; i-- { + if a.w[i] == b.w[i] { + continue + } + if a.w[i] > b.w[i] { + return 1 + } else { + return -1 + } + } + return 0 +} + +/* Copy from another DBIG */ +func (r *DBIG) copy(x *DBIG) { + for i := 0; i < DNLEN; i++ { + r.w[i] = x.w[i] + } +} + +/* Copy from another BIG to upper half */ +func (r *DBIG) ucopy(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = 0 + } + for i := NLEN; i < DNLEN; i++ { + r.w[i] = x.w[i-NLEN] + } +} + +func (r *DBIG) add(x *DBIG) { + for i := 0; i < DNLEN; i++ { + r.w[i] = r.w[i] + x.w[i] + } +} + +/* this-=x */ +func (r *DBIG) sub(x *DBIG) { + for i := 0; i < DNLEN; i++ { + r.w[i] = r.w[i] - x.w[i] + } +} + +/* this-=x */ +func (r *DBIG) rsub(x *DBIG) { + for i := 0; i < DNLEN; i++ { + r.w[i] = x.w[i] - r.w[i] + } +} + +/* general shift left */ +func (r *DBIG) shl(k uint) { + n := k % BASEBITS + m := int(k / BASEBITS) + + r.w[DNLEN-1] = (r.w[DNLEN-1-m] << n) | (r.w[DNLEN-m-2] >> (BASEBITS - n)) + for i := DNLEN - 2; i > m; i-- { + r.w[i] = ((r.w[i-m] << n) & BMASK) | (r.w[i-m-1] >> (BASEBITS - n)) + } + r.w[m] = (r.w[0] << n) & BMASK + for i := 0; i < m; i++ { + r.w[i] = 0 + } +} + +/* general shift right */ +func (r *DBIG) shr(k uint) { + n := (k % BASEBITS) + m := int(k / BASEBITS) + for i := 0; i < DNLEN-m-1; i++ { + r.w[i] = (r.w[m+i] >> n) | ((r.w[m+i+1] << (BASEBITS - n)) & BMASK) + } + r.w[DNLEN-m-1] = r.w[DNLEN-1] >> n + for i := DNLEN - m; i < DNLEN; i++ { + r.w[i] = 0 + } +} + +/* set x = x mod 2^m */ +func (r *DBIG) mod2m(m uint) { + wd := int(m / BASEBITS) + bt := m % BASEBITS + msk := (Chunk(1) << bt) - 1 + r.w[wd] &= msk + for i := wd + 1; i < DNLEN; i++ { + r.w[i] = 0 + } +} + +/* reduces this DBIG mod a BIG, and returns the BIG */ +func (r *DBIG) mod(c *BIG) *BIG { + r.norm() + m := NewDBIGscopy(c) + dr := NewDBIG() + + if dcomp(r, m) < 0 { + return NewBIGdcopy(r) + } + + m.shl(1) + k := 1 + + for dcomp(r, m) >= 0 { + m.shl(1) + k++ + } + + for k > 0 { + m.shr(1) + + dr.copy(r) + dr.sub(m) + dr.norm() + r.cmove(dr, int(1-((dr.w[DNLEN-1]>>uint(CHUNK-1))&1))) + k-- + } + return NewBIGdcopy(r) +} + +/* return this/c */ +func (r *DBIG) div(c *BIG) *BIG { + var d int + k := 0 + m := NewDBIGscopy(c) + a := NewBIGint(0) + e := NewBIGint(1) + sr := NewBIG() + dr := NewDBIG() + r.norm() + + for dcomp(r, m) >= 0 { + e.fshl(1) + m.shl(1) + k++ + } + + for k > 0 { + m.shr(1) + e.shr(1) + + dr.copy(r) + dr.sub(m) + dr.norm() + d = int(1 - ((dr.w[DNLEN-1] >> uint(CHUNK-1)) & 1)) + r.cmove(dr, d) + sr.copy(a) + sr.add(e) + sr.norm() + a.cmove(sr, d) + + k-- + } + return a +} + +/* Convert to Hex String */ +func (r *DBIG) toString() string { + s := "" + len := r.nbits() + + if len%4 == 0 { + len /= 4 + } else { + len /= 4 + len++ + + } + + for i := len - 1; i >= 0; i-- { + b := NewDBIGcopy(r) + + b.shr(uint(i * 4)) + s += strconv.FormatInt(int64(b.w[0]&15), 16) + } + return s +} + +/* return number of bits */ +func (r *DBIG) nbits() int { + k := DNLEN - 1 + t := NewDBIGcopy(r) + t.norm() + for k >= 0 && t.w[k] == 0 { + k-- + } + if k < 0 { + return 0 + } + bts := int(BASEBITS) * k + c := t.w[k] + for c != 0 { + c /= 2 + bts++ + } + return bts +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH.go index 7fa0d171f9f..ff8e75a0f24 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -21,7 +23,6 @@ under the License. package FP256BN - import "github.com/hyperledger/fabric-amcl/amcl" const INVALID_PUBLIC_KEY int = -2 diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH_32.go new file mode 100644 index 00000000000..a17e6d894c2 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECDH_32.go @@ -0,0 +1,703 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* Elliptic Curve API high-level functions */ + +package FP256BN + +import "github.com/hyperledger/fabric-amcl/amcl" + +const INVALID_PUBLIC_KEY int = -2 +const ERROR int = -3 +const INVALID int = -4 +const EFS int = int(MODBYTES) +const EGS int = int(MODBYTES) + +/* Convert Integer to n-byte array */ +func inttoBytes(n int, len int) []byte { + var b []byte + var i int + for i = 0; i < len; i++ { + b = append(b, 0) + } + i = len + for n > 0 && i > 0 { + i-- + b[i] = byte(n & 0xff) + n /= 256 + } + return b +} + +func ehashit(sha int, A []byte, n int, B []byte, pad int) []byte { + var R []byte + if sha == amcl.SHA256 { + H := amcl.NewHASH256() + H.Process_array(A) + if n > 0 { + H.Process_num(int32(n)) + } + if B != nil { + H.Process_array(B) + } + R = H.Hash() + } + if sha == amcl.SHA384 { + H := amcl.NewHASH384() + H.Process_array(A) + if n > 0 { + H.Process_num(int32(n)) + } + if B != nil { + H.Process_array(B) + } + R = H.Hash() + } + if sha == amcl.SHA512 { + H := amcl.NewHASH512() + H.Process_array(A) + if n > 0 { + H.Process_num(int32(n)) + } + if B != nil { + H.Process_array(B) + } + R = H.Hash() + } + if R == nil { + return nil + } + + if pad == 0 { + return R + } + var W []byte + for i := 0; i < pad; i++ { + W = append(W, 0) + } + if pad <= sha { + for i := 0; i < pad; i++ { + W[i] = R[i] + } + } else { + for i := 0; i < sha; i++ { + W[i+pad-sha] = R[i] + } + for i := 0; i < pad-sha; i++ { + W[i] = 0 + } + } + return W +} + +/* Key Derivation Functions */ +/* Input octet Z */ +/* Output key of length olen */ +func ECDH_KDF1(sha int, Z []byte, olen int) []byte { + /* NOTE: the parameter olen is the length of the output K in bytes */ + hlen := sha + var K []byte + k := 0 + + for i := 0; i < olen; i++ { + K = append(K, 0) + } + + cthreshold := olen / hlen + if olen%hlen != 0 { + cthreshold++ + } + + for counter := 0; counter < cthreshold; counter++ { + B := ehashit(sha, Z, counter, nil, 0) + if k+hlen > olen { + for i := 0; i < olen%hlen; i++ { + K[k] = B[i] + k++ + } + } else { + for i := 0; i < hlen; i++ { + K[k] = B[i] + k++ + } + } + } + return K +} + +func ECDH_KDF2(sha int, Z []byte, P []byte, olen int) []byte { + /* NOTE: the parameter olen is the length of the output k in bytes */ + hlen := sha + var K []byte + k := 0 + + for i := 0; i < olen; i++ { + K = append(K, 0) + } + + cthreshold := olen / hlen + if olen%hlen != 0 { + cthreshold++ + } + + for counter := 1; counter <= cthreshold; counter++ { + B := ehashit(sha, Z, counter, P, 0) + if k+hlen > olen { + for i := 0; i < olen%hlen; i++ { + K[k] = B[i] + k++ + } + } else { + for i := 0; i < hlen; i++ { + K[k] = B[i] + k++ + } + } + } + return K +} + +/* Password based Key Derivation Function */ +/* Input password p, salt s, and repeat count */ +/* Output key of length olen */ +func ECDH_PBKDF2(sha int, Pass []byte, Salt []byte, rep int, olen int) []byte { + d := olen / sha + if olen%sha != 0 { + d++ + } + + var F []byte + var U []byte + var S []byte + var K []byte + + for i := 0; i < sha; i++ { + F = append(F, 0) + U = append(U, 0) + } + + for i := 1; i <= d; i++ { + for j := 0; j < len(Salt); j++ { + S = append(S, Salt[j]) + } + N := inttoBytes(i, 4) + for j := 0; j < 4; j++ { + S = append(S, N[j]) + } + + HMAC(sha, S, Pass, F[:]) + + for j := 0; j < sha; j++ { + U[j] = F[j] + } + for j := 2; j <= rep; j++ { + HMAC(sha, U[:], Pass, U[:]) + for k := 0; k < sha; k++ { + F[k] ^= U[k] + } + } + for j := 0; j < sha; j++ { + K = append(K, F[j]) + } + } + var key []byte + for i := 0; i < olen; i++ { + key = append(key, K[i]) + } + return key +} + +/* Calculate HMAC of m using key k. HMAC is tag of length olen (which is length of tag) */ +func HMAC(sha int, M []byte, K []byte, tag []byte) int { + /* Input is from an octet m * + * olen is requested output length in bytes. k is the key * + * The output is the calculated tag */ + var B []byte + b := 64 + if sha > 32 { + b = 128 + } + + var K0 [128]byte + olen := len(tag) + + if olen < 4 { + return 0 + } + + for i := 0; i < b; i++ { + K0[i] = 0 + } + + if len(K) > b { + B = ehashit(sha, K, 0, nil, 0) + for i := 0; i < sha; i++ { + K0[i] = B[i] + } + } else { + for i := 0; i < len(K); i++ { + K0[i] = K[i] + } + } + + for i := 0; i < b; i++ { + K0[i] ^= 0x36 + } + B = ehashit(sha, K0[0:b], 0, M, 0) + + for i := 0; i < b; i++ { + K0[i] ^= 0x6a + } + B = ehashit(sha, K0[0:b], 0, B, olen) + + for i := 0; i < olen; i++ { + tag[i] = B[i] + } + + return 1 +} + +/* AES encryption/decryption. Encrypt byte array M using key K and returns ciphertext */ +func AES_CBC_IV0_ENCRYPT(K []byte, M []byte) []byte { /* AES CBC encryption, with Null IV and key K */ + /* Input is from an octet string M, output is to an octet string C */ + /* Input is padded as necessary to make up a full final block */ + a := amcl.NewAES() + fin := false + + var buff [16]byte + var C []byte + + a.Init(amcl.AES_CBC, len(K), K, nil) + + ipt := 0 //opt:=0 + var i int + for true { + for i = 0; i < 16; i++ { + if ipt < len(M) { + buff[i] = M[ipt] + ipt++ + } else { + fin = true + break + } + } + if fin { + break + } + a.Encrypt(buff[:]) + for i = 0; i < 16; i++ { + C = append(C, buff[i]) + } + } + + /* last block, filled up to i-th index */ + + padlen := 16 - i + for j := i; j < 16; j++ { + buff[j] = byte(padlen) + } + + a.Encrypt(buff[:]) + + for i = 0; i < 16; i++ { + C = append(C, buff[i]) + } + a.End() + return C +} + +/* returns plaintext if all consistent, else returns null string */ +func AES_CBC_IV0_DECRYPT(K []byte, C []byte) []byte { /* padding is removed */ + a := amcl.NewAES() + var buff [16]byte + var MM []byte + var M []byte + + var i int + ipt := 0 + opt := 0 + + a.Init(amcl.AES_CBC, len(K), K, nil) + + if len(C) == 0 { + return nil + } + ch := C[ipt] + ipt++ + + fin := false + + for true { + for i = 0; i < 16; i++ { + buff[i] = ch + if ipt >= len(C) { + fin = true + break + } else { + ch = C[ipt] + ipt++ + } + } + a.Decrypt(buff[:]) + if fin { + break + } + for i = 0; i < 16; i++ { + MM = append(MM, buff[i]) + opt++ + } + } + + a.End() + bad := false + padlen := int(buff[15]) + if i != 15 || padlen < 1 || padlen > 16 { + bad = true + } + if padlen >= 2 && padlen <= 16 { + for i = 16 - padlen; i < 16; i++ { + if buff[i] != byte(padlen) { + bad = true + } + } + } + + if !bad { + for i = 0; i < 16-padlen; i++ { + MM = append(MM, buff[i]) + opt++ + } + } + + if bad { + return nil + } + + for i = 0; i < opt; i++ { + M = append(M, MM[i]) + } + + return M +} + +/* Calculate a public/private EC GF(p) key pair W,S where W=S.G mod EC(p), + * where S is the secret key and W is the public key + * and G is fixed generator. + * If RNG is NULL then the private key is provided externally in S + * otherwise it is generated randomly internally */ +func ECDH_KEY_PAIR_GENERATE(RNG *amcl.RAND, S []byte, W []byte) int { + res := 0 + var s *BIG + var G *ECP + + G = ECP_generator() + + r := NewBIGints(CURVE_Order) + + if RNG == nil { + s = FromBytes(S) + s.Mod(r) + } else { + s = Randomnum(r, RNG) + } + + s.ToBytes(S) + + WP := G.mul(s) + + WP.ToBytes(W, false) // To use point compression on public keys, change to true + + return res +} + +/* validate public key */ +func ECDH_PUBLIC_KEY_VALIDATE(W []byte) int { + WP := ECP_fromBytes(W) + res := 0 + + r := NewBIGints(CURVE_Order) + + if WP.Is_infinity() { + res = INVALID_PUBLIC_KEY + } + if res == 0 { + + q := NewBIGints(Modulus) + nb := q.nbits() + k := NewBIGint(1) + k.shl(uint((nb + 4) / 2)) + k.add(q) + k.div(r) + + for k.parity() == 0 { + k.shr(1) + WP.dbl() + } + + if !k.isunity() { + WP = WP.mul(k) + } + if WP.Is_infinity() { + res = INVALID_PUBLIC_KEY + } + + } + return res +} + +/* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */ +func ECDH_ECPSVDP_DH(S []byte, WD []byte, Z []byte) int { + res := 0 + var T [EFS]byte + + s := FromBytes(S) + + W := ECP_fromBytes(WD) + if W.Is_infinity() { + res = ERROR + } + + if res == 0 { + r := NewBIGints(CURVE_Order) + s.Mod(r) + W = W.mul(s) + if W.Is_infinity() { + res = ERROR + } else { + W.GetX().ToBytes(T[:]) + for i := 0; i < EFS; i++ { + Z[i] = T[i] + } + } + } + return res +} + +/* IEEE ECDSA Signature, C and D are signature on F using private key S */ +func ECDH_ECPSP_DSA(sha int, RNG *amcl.RAND, S []byte, F []byte, C []byte, D []byte) int { + var T [EFS]byte + + B := ehashit(sha, F, 0, nil, int(MODBYTES)) + G := ECP_generator() + + r := NewBIGints(CURVE_Order) + + s := FromBytes(S) + f := FromBytes(B[:]) + + c := NewBIGint(0) + d := NewBIGint(0) + V := NewECP() + + for d.iszilch() { + u := Randomnum(r, RNG) + w := Randomnum(r, RNG) /* side channel masking */ + V.Copy(G) + V = V.mul(u) + vx := V.GetX() + c.copy(vx) + c.Mod(r) + if c.iszilch() { + continue + } + u.copy(Modmul(u, w, r)) + u.Invmodp(r) + d.copy(Modmul(s, c, r)) + d.add(f) + d.copy(Modmul(d, w, r)) + d.copy(Modmul(u, d, r)) + } + + c.ToBytes(T[:]) + for i := 0; i < EFS; i++ { + C[i] = T[i] + } + d.ToBytes(T[:]) + for i := 0; i < EFS; i++ { + D[i] = T[i] + } + return 0 +} + +/* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */ +func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { + res := 0 + + B := ehashit(sha, F, 0, nil, int(MODBYTES)) + + G := ECP_generator() + r := NewBIGints(CURVE_Order) + + c := FromBytes(C) + d := FromBytes(D) + f := FromBytes(B[:]) + + if c.iszilch() || Comp(c, r) >= 0 || d.iszilch() || Comp(d, r) >= 0 { + res = INVALID + } + + if res == 0 { + d.Invmodp(r) + f.copy(Modmul(f, d, r)) + h2 := Modmul(c, d, r) + + WP := ECP_fromBytes(W) + if WP.Is_infinity() { + res = ERROR + } else { + P := NewECP() + P.Copy(WP) + + P = P.Mul2(h2, G, f) + + if P.Is_infinity() { + res = INVALID + } else { + d = P.GetX() + d.Mod(r) + + if Comp(d, c) != 0 { + res = INVALID + } + } + } + } + + return res +} + +/* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */ +func ECDH_ECIES_ENCRYPT(sha int, P1 []byte, P2 []byte, RNG *amcl.RAND, W []byte, M []byte, V []byte, T []byte) []byte { + var Z [EFS]byte + var VZ [3*EFS + 1]byte + var K1 [AESKEY]byte + var K2 [AESKEY]byte + var U [EGS]byte + + if ECDH_KEY_PAIR_GENERATE(RNG, U[:], V) != 0 { + return nil + } + if ECDH_ECPSVDP_DH(U[:], W, Z[:]) != 0 { + return nil + } + + for i := 0; i < 2*EFS+1; i++ { + VZ[i] = V[i] + } + for i := 0; i < EFS; i++ { + VZ[2*EFS+1+i] = Z[i] + } + + K := ECDH_KDF2(sha, VZ[:], P1, 2*AESKEY) + + for i := 0; i < AESKEY; i++ { + K1[i] = K[i] + K2[i] = K[AESKEY+i] + } + + C := AES_CBC_IV0_ENCRYPT(K1[:], M) + + L2 := inttoBytes(len(P2), 8) + + var AC []byte + + for i := 0; i < len(C); i++ { + AC = append(AC, C[i]) + } + for i := 0; i < len(P2); i++ { + AC = append(AC, P2[i]) + } + for i := 0; i < 8; i++ { + AC = append(AC, L2[i]) + } + + HMAC(sha, AC, K2[:], T) + + return C +} + +/* constant time n-byte compare */ +func ncomp(T1 []byte, T2 []byte, n int) bool { + res := 0 + for i := 0; i < n; i++ { + res |= int(T1[i] ^ T2[i]) + } + if res == 0 { + return true + } + return false +} + +/* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */ +func ECDH_ECIES_DECRYPT(sha int, P1 []byte, P2 []byte, V []byte, C []byte, T []byte, U []byte) []byte { + var Z [EFS]byte + var VZ [3*EFS + 1]byte + var K1 [AESKEY]byte + var K2 [AESKEY]byte + + var TAG []byte = T[:] + + if ECDH_ECPSVDP_DH(U, V, Z[:]) != 0 { + return nil + } + + for i := 0; i < 2*EFS+1; i++ { + VZ[i] = V[i] + } + for i := 0; i < EFS; i++ { + VZ[2*EFS+1+i] = Z[i] + } + + K := ECDH_KDF2(sha, VZ[:], P1, 2*AESKEY) + + for i := 0; i < AESKEY; i++ { + K1[i] = K[i] + K2[i] = K[AESKEY+i] + } + + M := AES_CBC_IV0_DECRYPT(K1[:], C) + + if M == nil { + return nil + } + + L2 := inttoBytes(len(P2), 8) + + var AC []byte + + for i := 0; i < len(C); i++ { + AC = append(AC, C[i]) + } + for i := 0; i < len(P2); i++ { + AC = append(AC, P2[i]) + } + for i := 0; i < 8; i++ { + AC = append(AC, L2[i]) + } + + HMAC(sha, AC, K2[:], TAG) + + if !ncomp(T, TAG, len(T)) { + return nil + } + + return M +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP.go index be6cb0a8eaf..18479ef16de 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -19,8 +21,6 @@ under the License. package FP256BN - - //const WEIERSTRASS int = 0 //const EDWARDS int = 1 //const MONTGOMERY int = 2 @@ -32,7 +32,6 @@ package FP256BN //const POSITIVEX int = 0 //const NEGATIVEX int = 1 - //const CURVETYPE int = @CT@ //const CURVE_PAIRING_TYPE int = @PF@ //const SEXTIC_TWIST int = @ST@ diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2.go index 0d34fe7383c..c59d9a4b31e 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -21,8 +23,6 @@ under the License. package FP256BN - - type ECP2 struct { x *FP2 y *FP2 diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2_32.go new file mode 100644 index 00000000000..5d6b208f60b --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP2_32.go @@ -0,0 +1,719 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* MiotCL Weierstrass elliptic curve functions over FP2 */ + +package FP256BN + +type ECP2 struct { + x *FP2 + y *FP2 + z *FP2 +} + +func NewECP2() *ECP2 { + E := new(ECP2) + E.x = NewFP2() + E.y = NewFP2int(1) + E.z = NewFP2() + return E +} + +/* Test this=O? */ +func (E *ECP2) Is_infinity() bool { + E.x.reduce() + E.y.reduce() + E.z.reduce() + return E.x.iszilch() && E.z.iszilch() +} + +/* copy this=P */ +func (E *ECP2) Copy(P *ECP2) { + E.x.copy(P.x) + E.y.copy(P.y) + E.z.copy(P.z) +} + +/* set this=O */ +func (E *ECP2) inf() { + E.x.zero() + E.y.one() + E.z.zero() +} + +/* set this=-this */ +func (E *ECP2) neg() { + E.y.norm() + E.y.neg() + E.y.norm() +} + +/* Conditional move of Q to P dependant on d */ +func (E *ECP2) cmove(Q *ECP2, d int) { + E.x.cmove(Q.x, d) + E.y.cmove(Q.y, d) + E.z.cmove(Q.z, d) +} + +/* Constant time select from pre-computed table */ +func (E *ECP2) selector(W []*ECP2, b int32) { + MP := NewECP2() + m := b >> 31 + babs := (b ^ m) - m + + babs = (babs - 1) / 2 + + E.cmove(W[0], teq(babs, 0)) // conditional move + E.cmove(W[1], teq(babs, 1)) + E.cmove(W[2], teq(babs, 2)) + E.cmove(W[3], teq(babs, 3)) + E.cmove(W[4], teq(babs, 4)) + E.cmove(W[5], teq(babs, 5)) + E.cmove(W[6], teq(babs, 6)) + E.cmove(W[7], teq(babs, 7)) + + MP.Copy(E) + MP.neg() + E.cmove(MP, int(m&1)) +} + +/* Test if P == Q */ +func (E *ECP2) Equals(Q *ECP2) bool { + + a := NewFP2copy(E.x) + b := NewFP2copy(Q.x) + a.mul(Q.z) + b.mul(E.z) + + if !a.Equals(b) { + return false + } + a.copy(E.y) + b.copy(Q.y) + a.mul(Q.z) + b.mul(E.z) + if !a.Equals(b) { + return false + } + + return true +} + +/* set to Affine - (x,y,z) to (x,y) */ +func (E *ECP2) Affine() { + if E.Is_infinity() { + return + } + one := NewFP2int(1) + if E.z.Equals(one) { + E.x.reduce() + E.y.reduce() + return + } + E.z.inverse() + + E.x.mul(E.z) + E.x.reduce() + E.y.mul(E.z) + E.y.reduce() + E.z.copy(one) +} + +/* extract affine x as FP2 */ +func (E *ECP2) GetX() *FP2 { + W := NewECP2() + W.Copy(E) + W.Affine() + return W.x +} + +/* extract affine y as FP2 */ +func (E *ECP2) GetY() *FP2 { + W := NewECP2() + W.Copy(E) + W.Affine() + return W.y +} + +/* extract projective x */ +func (E *ECP2) getx() *FP2 { + return E.x +} + +/* extract projective y */ +func (E *ECP2) gety() *FP2 { + return E.y +} + +/* extract projective z */ +func (E *ECP2) getz() *FP2 { + return E.z +} + +/* convert to byte array */ +func (E *ECP2) ToBytes(b []byte) { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + + W := NewECP2() + W.Copy(E) + W.Affine() + + W.x.GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + b[i] = t[i] + } + W.x.GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + b[i+MB] = t[i] + } + + W.y.GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + b[i+2*MB] = t[i] + } + W.y.GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + b[i+3*MB] = t[i] + } +} + +/* convert from byte array to point */ +func ECP2_fromBytes(b []byte) *ECP2 { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + + for i := 0; i < MB; i++ { + t[i] = b[i] + } + ra := FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = b[i+MB] + } + rb := FromBytes(t[:]) + rx := NewFP2bigs(ra, rb) + + for i := 0; i < MB; i++ { + t[i] = b[i+2*MB] + } + ra = FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = b[i+3*MB] + } + rb = FromBytes(t[:]) + ry := NewFP2bigs(ra, rb) + + return NewECP2fp2s(rx, ry) +} + +/* convert this to hex string */ +func (E *ECP2) ToString() string { + W := NewECP2() + W.Copy(E) + W.Affine() + if W.Is_infinity() { + return "infinity" + } + return "(" + W.x.toString() + "," + W.y.toString() + ")" +} + +/* Calculate RHS of twisted curve equation x^3+B/i */ +func RHS2(x *FP2) *FP2 { + r := NewFP2copy(x) + r.sqr() + b := NewFP2big(NewBIGints(CURVE_B)) + + if SEXTIC_TWIST == D_TYPE { + b.div_ip() + } + if SEXTIC_TWIST == M_TYPE { + b.norm() + b.mul_ip() + b.norm() + } + r.mul(x) + r.add(b) + + r.reduce() + return r +} + +/* construct this from (x,y) - but set to O if not on curve */ +func NewECP2fp2s(ix *FP2, iy *FP2) *ECP2 { + E := new(ECP2) + E.x = NewFP2copy(ix) + E.y = NewFP2copy(iy) + E.z = NewFP2int(1) + E.x.norm() + rhs := RHS2(E.x) + y2 := NewFP2copy(E.y) + y2.sqr() + if !y2.Equals(rhs) { + E.inf() + } + return E +} + +/* construct this from x - but set to O if not on curve */ +func NewECP2fp2(ix *FP2) *ECP2 { + E := new(ECP2) + E.x = NewFP2copy(ix) + E.y = NewFP2int(1) + E.z = NewFP2int(1) + E.x.norm() + rhs := RHS2(E.x) + if rhs.sqrt() { + E.y.copy(rhs) + } else { + E.inf() + } + return E +} + +/* this+=this */ +func (E *ECP2) dbl() int { + iy := NewFP2copy(E.y) + if SEXTIC_TWIST == D_TYPE { + iy.mul_ip() + iy.norm() + } + + t0 := NewFP2copy(E.y) //***** Change + t0.sqr() + if SEXTIC_TWIST == D_TYPE { + t0.mul_ip() + } + t1 := NewFP2copy(iy) + t1.mul(E.z) + t2 := NewFP2copy(E.z) + t2.sqr() // z^2 + + E.z.copy(t0) // y^2 + E.z.add(t0) + E.z.norm() // 2y^2 + E.z.add(E.z) + E.z.add(E.z) // 8y^2 + E.z.norm() + + t2.imul(3 * CURVE_B_I) // 3bz^2 + if SEXTIC_TWIST == M_TYPE { + t2.mul_ip() + t2.norm() + } + x3 := NewFP2copy(t2) + x3.mul(E.z) + + y3 := NewFP2copy(t0) + + y3.add(t2) + y3.norm() + E.z.mul(t1) + t1.copy(t2) + t1.add(t2) + t2.add(t1) + t2.norm() + t0.sub(t2) + t0.norm() //y^2-9bz^2 + y3.mul(t0) + y3.add(x3) //(y^2+3z*2)(y^2-9z^2)+3b.z^2.8y^2 + t1.copy(E.x) + t1.mul(iy) // + E.x.copy(t0) + E.x.norm() + E.x.mul(t1) + E.x.add(E.x) //(y^2-9bz^2)xy2 + + E.x.norm() + E.y.copy(y3) + E.y.norm() + + return 1 +} + +/* this+=Q - return 0 for add, 1 for double, -1 for O */ +func (E *ECP2) Add(Q *ECP2) int { + b := 3 * CURVE_B_I + t0 := NewFP2copy(E.x) + t0.mul(Q.x) // x.Q.x + t1 := NewFP2copy(E.y) + t1.mul(Q.y) // y.Q.y + + t2 := NewFP2copy(E.z) + t2.mul(Q.z) + t3 := NewFP2copy(E.x) + t3.add(E.y) + t3.norm() //t3=X1+Y1 + t4 := NewFP2copy(Q.x) + t4.add(Q.y) + t4.norm() //t4=X2+Y2 + t3.mul(t4) //t3=(X1+Y1)(X2+Y2) + t4.copy(t0) + t4.add(t1) //t4=X1.X2+Y1.Y2 + + t3.sub(t4) + t3.norm() + if SEXTIC_TWIST == D_TYPE { + t3.mul_ip() + t3.norm() //t3=(X1+Y1)(X2+Y2)-(X1.X2+Y1.Y2) = X1.Y2+X2.Y1 + } + t4.copy(E.y) + t4.add(E.z) + t4.norm() //t4=Y1+Z1 + x3 := NewFP2copy(Q.y) + x3.add(Q.z) + x3.norm() //x3=Y2+Z2 + + t4.mul(x3) //t4=(Y1+Z1)(Y2+Z2) + x3.copy(t1) // + x3.add(t2) //X3=Y1.Y2+Z1.Z2 + + t4.sub(x3) + t4.norm() + if SEXTIC_TWIST == D_TYPE { + t4.mul_ip() + t4.norm() //t4=(Y1+Z1)(Y2+Z2) - (Y1.Y2+Z1.Z2) = Y1.Z2+Y2.Z1 + } + x3.copy(E.x) + x3.add(E.z) + x3.norm() // x3=X1+Z1 + y3 := NewFP2copy(Q.x) + y3.add(Q.z) + y3.norm() // y3=X2+Z2 + x3.mul(y3) // x3=(X1+Z1)(X2+Z2) + y3.copy(t0) + y3.add(t2) // y3=X1.X2+Z1+Z2 + y3.rsub(x3) + y3.norm() // y3=(X1+Z1)(X2+Z2) - (X1.X2+Z1.Z2) = X1.Z2+X2.Z1 + + if SEXTIC_TWIST == D_TYPE { + t0.mul_ip() + t0.norm() // x.Q.x + t1.mul_ip() + t1.norm() // y.Q.y + } + x3.copy(t0) + x3.add(t0) + t0.add(x3) + t0.norm() + t2.imul(b) + if SEXTIC_TWIST == M_TYPE { + t2.mul_ip() + t2.norm() + } + z3 := NewFP2copy(t1) + z3.add(t2) + z3.norm() + t1.sub(t2) + t1.norm() + y3.imul(b) + if SEXTIC_TWIST == M_TYPE { + y3.mul_ip() + y3.norm() + } + x3.copy(y3) + x3.mul(t4) + t2.copy(t3) + t2.mul(t1) + x3.rsub(t2) + y3.mul(t0) + t1.mul(z3) + y3.add(t1) + t0.mul(t3) + z3.mul(t4) + z3.add(t0) + + E.x.copy(x3) + E.x.norm() + E.y.copy(y3) + E.y.norm() + E.z.copy(z3) + E.z.norm() + + return 0 +} + +/* set this-=Q */ +func (E *ECP2) Sub(Q *ECP2) int { + NQ := NewECP2() + NQ.Copy(Q) + NQ.neg() + D := E.Add(NQ) + return D +} + +/* set this*=q, where q is Modulus, using Frobenius */ +func (E *ECP2) frob(X *FP2) { + X2 := NewFP2copy(X) + X2.sqr() + E.x.conj() + E.y.conj() + E.z.conj() + E.z.reduce() + E.x.mul(X2) + E.y.mul(X2) + E.y.mul(X) +} + +/* P*=e */ +func (E *ECP2) mul(e *BIG) *ECP2 { + /* fixed size windows */ + mt := NewBIG() + t := NewBIG() + P := NewECP2() + Q := NewECP2() + C := NewECP2() + + if E.Is_infinity() { + return NewECP2() + } + + var W []*ECP2 + var w [1 + (NLEN*int(BASEBITS)+3)/4]int8 + + /* precompute table */ + Q.Copy(E) + Q.dbl() + + W = append(W, NewECP2()) + W[0].Copy(E) + + for i := 1; i < 8; i++ { + W = append(W, NewECP2()) + W[i].Copy(W[i-1]) + W[i].Add(Q) + } + + /* make exponent odd - add 2P if even, P if odd */ + t.copy(e) + s := int(t.parity()) + t.inc(1) + t.norm() + ns := int(t.parity()) + mt.copy(t) + mt.inc(1) + mt.norm() + t.cmove(mt, s) + Q.cmove(E, ns) + C.Copy(Q) + + nb := 1 + (t.nbits()+3)/4 + /* convert exponent to signed 4-bit window */ + for i := 0; i < nb; i++ { + w[i] = int8(t.lastbits(5) - 16) + t.dec(int(w[i])) + t.norm() + t.fshr(4) + } + w[nb] = int8(t.lastbits(5)) + + P.Copy(W[(w[nb]-1)/2]) + for i := nb - 1; i >= 0; i-- { + Q.selector(W, int32(w[i])) + P.dbl() + P.dbl() + P.dbl() + P.dbl() + P.Add(Q) + } + P.Sub(C) + P.Affine() + return P +} + +/* Public version */ +func (E *ECP2) Mul(e *BIG) *ECP2 { + return E.mul(e) +} + +/* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3 */ +// Bos & Costello https://eprint.iacr.org/2013/458.pdf +// Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf +// Side channel attack secure +func mul4(Q []*ECP2, u []*BIG) *ECP2 { + W := NewECP2() + P := NewECP2() + var T []*ECP2 + mt := NewBIG() + var t []*BIG + + var w [NLEN*int(BASEBITS) + 1]int8 + var s [NLEN*int(BASEBITS) + 1]int8 + + for i := 0; i < 4; i++ { + t = append(t, NewBIGcopy(u[i])) + } + + T = append(T, NewECP2()) + T[0].Copy(Q[0]) // Q[0] + T = append(T, NewECP2()) + T[1].Copy(T[0]) + T[1].Add(Q[1]) // Q[0]+Q[1] + T = append(T, NewECP2()) + T[2].Copy(T[0]) + T[2].Add(Q[2]) // Q[0]+Q[2] + T = append(T, NewECP2()) + T[3].Copy(T[1]) + T[3].Add(Q[2]) // Q[0]+Q[1]+Q[2] + T = append(T, NewECP2()) + T[4].Copy(T[0]) + T[4].Add(Q[3]) // Q[0]+Q[3] + T = append(T, NewECP2()) + T[5].Copy(T[1]) + T[5].Add(Q[3]) // Q[0]+Q[1]+Q[3] + T = append(T, NewECP2()) + T[6].Copy(T[2]) + T[6].Add(Q[3]) // Q[0]+Q[2]+Q[3] + T = append(T, NewECP2()) + T[7].Copy(T[3]) + T[7].Add(Q[3]) // Q[0]+Q[1]+Q[2]+Q[3] + + // Make it odd + pb := 1 - t[0].parity() + t[0].inc(pb) + + // Number of bits + mt.zero() + for i := 0; i < 4; i++ { + t[i].norm() + mt.or(t[i]) + } + + nb := 1 + mt.nbits() + + // Sign pivot + s[nb-1] = 1 + for i := 0; i < nb-1; i++ { + t[0].fshr(1) + s[i] = 2*int8(t[0].parity()) - 1 + } + + // Recoded exponent + for i := 0; i < nb; i++ { + w[i] = 0 + k := 1 + for j := 1; j < 4; j++ { + bt := s[i] * int8(t[j].parity()) + t[j].fshr(1) + t[j].dec(int(bt) >> 1) + t[j].norm() + w[i] += bt * int8(k) + k *= 2 + } + } + + // Main loop + P.selector(T, int32(2*w[nb-1]+1)) + for i := nb - 2; i >= 0; i-- { + P.dbl() + W.selector(T, int32(2*w[i]+s[i])) + P.Add(W) + } + + // apply correction + W.Copy(P) + W.Sub(Q[0]) + P.cmove(W, pb) + + P.Affine() + return P +} + +/* needed for SOK */ +func ECP2_mapit(h []byte) *ECP2 { + q := NewBIGints(Modulus) + x := FromBytes(h[:]) + one := NewBIGint(1) + var X *FP2 + var Q, T, K, xQ, x2Q *ECP2 + x.Mod(q) + for true { + X = NewFP2bigs(one, x) + Q = NewECP2fp2(X) + if !Q.Is_infinity() { + break + } + x.inc(1) + x.norm() + } + /* Fast Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez */ + Fra := NewBIGints(Fra) + Frb := NewBIGints(Frb) + X = NewFP2bigs(Fra, Frb) + if SEXTIC_TWIST == M_TYPE { + X.inverse() + X.norm() + } + + x = NewBIGints(CURVE_Bnx) + + if CURVE_PAIRING_TYPE == BN { + T = NewECP2() + T.Copy(Q) + T = T.mul(x) + if SIGN_OF_X == NEGATIVEX { + T.neg() + } + + K = NewECP2() + K.Copy(T) + K.dbl() + K.Add(T) + + K.frob(X) + Q.frob(X) + Q.frob(X) + Q.frob(X) + Q.Add(T) + Q.Add(K) + T.frob(X) + T.frob(X) + Q.Add(T) + } + if CURVE_PAIRING_TYPE == BLS { + xQ = Q.mul(x) + x2Q = xQ.mul(x) + + if SIGN_OF_X == NEGATIVEX { + xQ.neg() + } + + x2Q.Sub(xQ) + x2Q.Sub(Q) + + xQ.Sub(Q) + xQ.frob(X) + + Q.dbl() + Q.frob(X) + Q.frob(X) + + Q.Add(x2Q) + Q.Add(xQ) + } + Q.Affine() + return Q +} + +func ECP2_generator() *ECP2 { + var G *ECP2 + G = NewECP2fp2s(NewFP2bigs(NewBIGints(CURVE_Pxa), NewBIGints(CURVE_Pxb)), NewFP2bigs(NewBIGints(CURVE_Pya), NewBIGints(CURVE_Pyb))) + return G +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP_32.go new file mode 100644 index 00000000000..0a91aa69458 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ECP_32.go @@ -0,0 +1,1219 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +package FP256BN + +//const WEIERSTRASS int = 0 +//const EDWARDS int = 1 +//const MONTGOMERY int = 2 +//const NOT int = 0 +//const BN int = 1 +//const BLS int = 2 +//const D_TYPE int = 0 +//const M_TYPE int = 1 +//const POSITIVEX int = 0 +//const NEGATIVEX int = 1 + +//const CURVETYPE int = @CT@ +//const CURVE_PAIRING_TYPE int = @PF@ +//const SEXTIC_TWIST int = @ST@ +//const SIGN_OF_X int = @SX@ + +//const HASH_TYPE int = @HT@ +//const AESKEY int = @AK@ + +/* Elliptic Curve Point Structure */ + +type ECP struct { + x *FP + y *FP + z *FP +} + +/* Constructors */ +func NewECP() *ECP { + E := new(ECP) + E.x = NewFP() + E.y = NewFPint(1) + if CURVETYPE == EDWARDS { + E.z = NewFPint(1) + } else { + E.z = NewFP() + } + return E +} + +/* set (x,y) from two BIGs */ +func NewECPbigs(ix *BIG, iy *BIG) *ECP { + E := new(ECP) + E.x = NewFPbig(ix) + E.y = NewFPbig(iy) + E.z = NewFPint(1) + E.x.norm() + rhs := RHS(E.x) + + if CURVETYPE == MONTGOMERY { + if rhs.jacobi() != 1 { + E.inf() + } + } else { + y2 := NewFPcopy(E.y) + y2.sqr() + if !y2.Equals(rhs) { + E.inf() + } + } + return E +} + +/* set (x,y) from BIG and a bit */ +func NewECPbigint(ix *BIG, s int) *ECP { + E := new(ECP) + E.x = NewFPbig(ix) + E.y = NewFP() + E.x.norm() + rhs := RHS(E.x) + E.z = NewFPint(1) + if rhs.jacobi() == 1 { + ny := rhs.sqrt() + if ny.redc().parity() != s { + ny.neg() + } + E.y.copy(ny) + } else { + E.inf() + } + return E +} + +/* set from x - calculate y from curve equation */ +func NewECPbig(ix *BIG) *ECP { + E := new(ECP) + E.x = NewFPbig(ix) + E.y = NewFP() + E.x.norm() + rhs := RHS(E.x) + E.z = NewFPint(1) + if rhs.jacobi() == 1 { + if CURVETYPE != MONTGOMERY { + E.y.copy(rhs.sqrt()) + } + } else { + E.inf() + } + return E +} + +/* test for O point-at-infinity */ +func (E *ECP) Is_infinity() bool { + // if E.INF {return true} + E.x.reduce() + E.z.reduce() + if CURVETYPE == EDWARDS { + E.y.reduce() + return (E.x.iszilch() && E.y.Equals(E.z)) + } + if CURVETYPE == WEIERSTRASS { + E.y.reduce() + return (E.x.iszilch() && E.z.iszilch()) + } + if CURVETYPE == MONTGOMERY { + return E.z.iszilch() + } + return true +} + +/* Conditional swap of P and Q dependant on d */ +func (E *ECP) cswap(Q *ECP, d int) { + E.x.cswap(Q.x, d) + if CURVETYPE != MONTGOMERY { + E.y.cswap(Q.y, d) + } + E.z.cswap(Q.z, d) +} + +/* Conditional move of Q to P dependant on d */ +func (E *ECP) cmove(Q *ECP, d int) { + E.x.cmove(Q.x, d) + if CURVETYPE != MONTGOMERY { + E.y.cmove(Q.y, d) + } + E.z.cmove(Q.z, d) +} + +/* return 1 if b==c, no branching */ +func teq(b int32, c int32) int { + x := b ^ c + x -= 1 // if x=0, x now -1 + return int((x >> 31) & 1) +} + +/* this=P */ +func (E *ECP) Copy(P *ECP) { + E.x.copy(P.x) + if CURVETYPE != MONTGOMERY { + E.y.copy(P.y) + } + E.z.copy(P.z) +} + +/* this=-this */ +func (E *ECP) neg() { + if CURVETYPE == WEIERSTRASS { + E.y.neg() + E.y.norm() + } + if CURVETYPE == EDWARDS { + E.x.neg() + E.x.norm() + } + return +} + +/* Constant time select from pre-computed table */ +func (E *ECP) selector(W []*ECP, b int32) { + MP := NewECP() + m := b >> 31 + babs := (b ^ m) - m + + babs = (babs - 1) / 2 + + E.cmove(W[0], teq(babs, 0)) // conditional move + E.cmove(W[1], teq(babs, 1)) + E.cmove(W[2], teq(babs, 2)) + E.cmove(W[3], teq(babs, 3)) + E.cmove(W[4], teq(babs, 4)) + E.cmove(W[5], teq(babs, 5)) + E.cmove(W[6], teq(babs, 6)) + E.cmove(W[7], teq(babs, 7)) + + MP.Copy(E) + MP.neg() + E.cmove(MP, int(m&1)) +} + +/* set this=O */ +func (E *ECP) inf() { + E.x.zero() + if CURVETYPE != MONTGOMERY { + E.y.one() + } + if CURVETYPE != EDWARDS { + E.z.zero() + } else { + E.z.one() + } +} + +/* Test P == Q */ +func (E *ECP) Equals(Q *ECP) bool { + a := NewFP() + b := NewFP() + a.copy(E.x) + a.mul(Q.z) + a.reduce() + b.copy(Q.x) + b.mul(E.z) + b.reduce() + if !a.Equals(b) { + return false + } + if CURVETYPE != MONTGOMERY { + a.copy(E.y) + a.mul(Q.z) + a.reduce() + b.copy(Q.y) + b.mul(E.z) + b.reduce() + if !a.Equals(b) { + return false + } + } + + return true +} + +/* Calculate RHS of curve equation */ +func RHS(x *FP) *FP { + r := NewFPcopy(x) + r.sqr() + + if CURVETYPE == WEIERSTRASS { // x^3+Ax+B + b := NewFPbig(NewBIGints(CURVE_B)) + r.mul(x) + if CURVE_A == -3 { + cx := NewFPcopy(x) + cx.imul(3) + cx.neg() + cx.norm() + r.add(cx) + } + r.add(b) + } + if CURVETYPE == EDWARDS { // (Ax^2-1)/(Bx^2-1) + b := NewFPbig(NewBIGints(CURVE_B)) + + one := NewFPint(1) + b.mul(r) + b.sub(one) + b.norm() + if CURVE_A == -1 { + r.neg() + } + r.sub(one) + r.norm() + b.inverse() + r.mul(b) + } + if CURVETYPE == MONTGOMERY { // x^3+Ax^2+x + x3 := NewFP() + x3.copy(r) + x3.mul(x) + r.imul(CURVE_A) + r.add(x3) + r.add(x) + } + r.reduce() + return r +} + +/* set to affine - from (x,y,z) to (x,y) */ +func (E *ECP) Affine() { + if E.Is_infinity() { + return + } + one := NewFPint(1) + if E.z.Equals(one) { + return + } + E.z.inverse() + E.x.mul(E.z) + E.x.reduce() + + if CURVETYPE != MONTGOMERY { + E.y.mul(E.z) + E.y.reduce() + } + E.z.copy(one) +} + +/* extract x as a BIG */ +func (E *ECP) GetX() *BIG { + W := NewECP() + W.Copy(E) + W.Affine() + return W.x.redc() +} + +/* extract y as a BIG */ +func (E *ECP) GetY() *BIG { + W := NewECP() + W.Copy(E) + W.Affine() + return W.y.redc() +} + +/* get sign of Y */ +func (E *ECP) GetS() int { + y := E.GetY() + return y.parity() +} + +/* extract x as an FP */ +func (E *ECP) getx() *FP { + return E.x +} + +/* extract y as an FP */ +func (E *ECP) gety() *FP { + return E.y +} + +/* extract z as an FP */ +func (E *ECP) getz() *FP { + return E.z +} + +/* convert to byte array */ +func (E *ECP) ToBytes(b []byte, compress bool) { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + W := NewECP() + W.Copy(E) + W.Affine() + W.x.redc().ToBytes(t[:]) + for i := 0; i < MB; i++ { + b[i+1] = t[i] + } + + if CURVETYPE == MONTGOMERY { + b[0] = 0x06 + return + } + + if compress { + b[0] = 0x02 + if W.y.redc().parity() == 1 { + b[0] = 0x03 + } + return + } + + b[0] = 0x04 + + W.y.redc().ToBytes(t[:]) + for i := 0; i < MB; i++ { + b[i+MB+1] = t[i] + } +} + +/* convert from byte array to point */ +func ECP_fromBytes(b []byte) *ECP { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + p := NewBIGints(Modulus) + + for i := 0; i < MB; i++ { + t[i] = b[i+1] + } + px := FromBytes(t[:]) + if Comp(px, p) >= 0 { + return NewECP() + } + + if CURVETYPE == MONTGOMERY { + return NewECPbig(px) + } + + if b[0] == 0x04 { + for i := 0; i < MB; i++ { + t[i] = b[i+MB+1] + } + py := FromBytes(t[:]) + if Comp(py, p) >= 0 { + return NewECP() + } + return NewECPbigs(px, py) + } + + if b[0] == 0x02 || b[0] == 0x03 { + return NewECPbigint(px, int(b[0]&1)) + } + + return NewECP() +} + +/* convert to hex string */ +func (E *ECP) ToString() string { + W := NewECP() + W.Copy(E) + W.Affine() + if W.Is_infinity() { + return "infinity" + } + if CURVETYPE == MONTGOMERY { + return "(" + W.x.redc().ToString() + ")" + } else { + return "(" + W.x.redc().ToString() + "," + W.y.redc().ToString() + ")" + } +} + +/* this*=2 */ +func (E *ECP) dbl() { + + if CURVETYPE == WEIERSTRASS { + if CURVE_A == 0 { + t0 := NewFPcopy(E.y) + t0.sqr() + t1 := NewFPcopy(E.y) + t1.mul(E.z) + t2 := NewFPcopy(E.z) + t2.sqr() + + E.z.copy(t0) + E.z.add(t0) + E.z.norm() + E.z.add(E.z) + E.z.add(E.z) + E.z.norm() + t2.imul(3 * CURVE_B_I) + + x3 := NewFPcopy(t2) + x3.mul(E.z) + + y3 := NewFPcopy(t0) + y3.add(t2) + y3.norm() + E.z.mul(t1) + t1.copy(t2) + t1.add(t2) + t2.add(t1) + t0.sub(t2) + t0.norm() + y3.mul(t0) + y3.add(x3) + t1.copy(E.x) + t1.mul(E.y) + E.x.copy(t0) + E.x.norm() + E.x.mul(t1) + E.x.add(E.x) + E.x.norm() + E.y.copy(y3) + E.y.norm() + } else { + t0 := NewFPcopy(E.x) + t1 := NewFPcopy(E.y) + t2 := NewFPcopy(E.z) + t3 := NewFPcopy(E.x) + z3 := NewFPcopy(E.z) + y3 := NewFP() + x3 := NewFP() + b := NewFP() + + if CURVE_B_I == 0 { + b.copy(NewFPbig(NewBIGints(CURVE_B))) + } + + t0.sqr() //1 x^2 + t1.sqr() //2 y^2 + t2.sqr() //3 + + t3.mul(E.y) //4 + t3.add(t3) + t3.norm() //5 + z3.mul(E.x) //6 + z3.add(z3) + z3.norm() //7 + y3.copy(t2) + + if CURVE_B_I == 0 { + y3.mul(b) + } else { + y3.imul(CURVE_B_I) + } + + y3.sub(z3) //9 *** + x3.copy(y3) + x3.add(y3) + x3.norm() //10 + + y3.add(x3) //11 + x3.copy(t1) + x3.sub(y3) + x3.norm() //12 + y3.add(t1) + y3.norm() //13 + y3.mul(x3) //14 + x3.mul(t3) //15 + t3.copy(t2) + t3.add(t2) //16 + t2.add(t3) //17 + + if CURVE_B_I == 0 { + z3.mul(b) + } else { + z3.imul(CURVE_B_I) + } + + z3.sub(t2) //19 + z3.sub(t0) + z3.norm() //20 *** + t3.copy(z3) + t3.add(z3) //21 + + z3.add(t3) + z3.norm() //22 + t3.copy(t0) + t3.add(t0) //23 + t0.add(t3) //24 + t0.sub(t2) + t0.norm() //25 + + t0.mul(z3) //26 + y3.add(t0) //27 + t0.copy(E.y) + t0.mul(E.z) //28 + t0.add(t0) + t0.norm() //29 + z3.mul(t0) //30 + x3.sub(z3) //x3.norm();//31 + t0.add(t0) + t0.norm() //32 + t1.add(t1) + t1.norm() //33 + z3.copy(t0) + z3.mul(t1) //34 + + E.x.copy(x3) + E.x.norm() + E.y.copy(y3) + E.y.norm() + E.z.copy(z3) + E.z.norm() + } + } + + if CURVETYPE == EDWARDS { + C := NewFPcopy(E.x) + D := NewFPcopy(E.y) + H := NewFPcopy(E.z) + J := NewFP() + + E.x.mul(E.y) + E.x.add(E.x) + E.x.norm() + C.sqr() + D.sqr() + if CURVE_A == -1 { + C.neg() + } + E.y.copy(C) + E.y.add(D) + E.y.norm() + + H.sqr() + H.add(H) + E.z.copy(E.y) + J.copy(E.y) + J.sub(H) + J.norm() + E.x.mul(J) + C.sub(D) + C.norm() + E.y.mul(C) + E.z.mul(J) + + } + if CURVETYPE == MONTGOMERY { + A := NewFPcopy(E.x) + B := NewFPcopy(E.x) + AA := NewFP() + BB := NewFP() + C := NewFP() + + A.add(E.z) + A.norm() + AA.copy(A) + AA.sqr() + B.sub(E.z) + B.norm() + BB.copy(B) + BB.sqr() + C.copy(AA) + C.sub(BB) + C.norm() + + E.x.copy(AA) + E.x.mul(BB) + + A.copy(C) + A.imul((CURVE_A + 2) / 4) + + BB.add(A) + BB.norm() + E.z.copy(BB) + E.z.mul(C) + } + return +} + +/* this+=Q */ +func (E *ECP) Add(Q *ECP) { + + if CURVETYPE == WEIERSTRASS { + if CURVE_A == 0 { + b := 3 * CURVE_B_I + t0 := NewFPcopy(E.x) + t0.mul(Q.x) + t1 := NewFPcopy(E.y) + t1.mul(Q.y) + t2 := NewFPcopy(E.z) + t2.mul(Q.z) + t3 := NewFPcopy(E.x) + t3.add(E.y) + t3.norm() + t4 := NewFPcopy(Q.x) + t4.add(Q.y) + t4.norm() + t3.mul(t4) + t4.copy(t0) + t4.add(t1) + + t3.sub(t4) + t3.norm() + t4.copy(E.y) + t4.add(E.z) + t4.norm() + x3 := NewFPcopy(Q.y) + x3.add(Q.z) + x3.norm() + + t4.mul(x3) + x3.copy(t1) + x3.add(t2) + + t4.sub(x3) + t4.norm() + x3.copy(E.x) + x3.add(E.z) + x3.norm() + y3 := NewFPcopy(Q.x) + y3.add(Q.z) + y3.norm() + x3.mul(y3) + y3.copy(t0) + y3.add(t2) + y3.rsub(x3) + y3.norm() + x3.copy(t0) + x3.add(t0) + t0.add(x3) + t0.norm() + t2.imul(b) + + z3 := NewFPcopy(t1) + z3.add(t2) + z3.norm() + t1.sub(t2) + t1.norm() + y3.imul(b) + + x3.copy(y3) + x3.mul(t4) + t2.copy(t3) + t2.mul(t1) + x3.rsub(t2) + y3.mul(t0) + t1.mul(z3) + y3.add(t1) + t0.mul(t3) + z3.mul(t4) + z3.add(t0) + + E.x.copy(x3) + E.x.norm() + E.y.copy(y3) + E.y.norm() + E.z.copy(z3) + E.z.norm() + } else { + + t0 := NewFPcopy(E.x) + t1 := NewFPcopy(E.y) + t2 := NewFPcopy(E.z) + t3 := NewFPcopy(E.x) + t4 := NewFPcopy(Q.x) + z3 := NewFP() + y3 := NewFPcopy(Q.x) + x3 := NewFPcopy(Q.y) + b := NewFP() + + if CURVE_B_I == 0 { + b.copy(NewFPbig(NewBIGints(CURVE_B))) + } + + t0.mul(Q.x) //1 + t1.mul(Q.y) //2 + t2.mul(Q.z) //3 + + t3.add(E.y) + t3.norm() //4 + t4.add(Q.y) + t4.norm() //5 + t3.mul(t4) //6 + t4.copy(t0) + t4.add(t1) //7 + t3.sub(t4) + t3.norm() //8 + t4.copy(E.y) + t4.add(E.z) + t4.norm() //9 + x3.add(Q.z) + x3.norm() //10 + t4.mul(x3) //11 + x3.copy(t1) + x3.add(t2) //12 + + t4.sub(x3) + t4.norm() //13 + x3.copy(E.x) + x3.add(E.z) + x3.norm() //14 + y3.add(Q.z) + y3.norm() //15 + + x3.mul(y3) //16 + y3.copy(t0) + y3.add(t2) //17 + + y3.rsub(x3) + y3.norm() //18 + z3.copy(t2) + + if CURVE_B_I == 0 { + z3.mul(b) + } else { + z3.imul(CURVE_B_I) + } + + x3.copy(y3) + x3.sub(z3) + x3.norm() //20 + z3.copy(x3) + z3.add(x3) //21 + + x3.add(z3) //22 + z3.copy(t1) + z3.sub(x3) + z3.norm() //23 + x3.add(t1) + x3.norm() //24 + + if CURVE_B_I == 0 { + y3.mul(b) + } else { + y3.imul(CURVE_B_I) + } + + t1.copy(t2) + t1.add(t2) //26 + t2.add(t1) //27 + + y3.sub(t2) //28 + + y3.sub(t0) + y3.norm() //29 + t1.copy(y3) + t1.add(y3) //30 + y3.add(t1) + y3.norm() //31 + + t1.copy(t0) + t1.add(t0) //32 + t0.add(t1) //33 + t0.sub(t2) + t0.norm() //34 + t1.copy(t4) + t1.mul(y3) //35 + t2.copy(t0) + t2.mul(y3) //36 + y3.copy(x3) + y3.mul(z3) //37 + y3.add(t2) //38 + x3.mul(t3) //39 + x3.sub(t1) //40 + z3.mul(t4) //41 + t1.copy(t3) + t1.mul(t0) //42 + z3.add(t1) + E.x.copy(x3) + E.x.norm() + E.y.copy(y3) + E.y.norm() + E.z.copy(z3) + E.z.norm() + + } + } + if CURVETYPE == EDWARDS { + b := NewFPbig(NewBIGints(CURVE_B)) + A := NewFPcopy(E.z) + B := NewFP() + C := NewFPcopy(E.x) + D := NewFPcopy(E.y) + EE := NewFP() + F := NewFP() + G := NewFP() + + A.mul(Q.z) + B.copy(A) + B.sqr() + C.mul(Q.x) + D.mul(Q.y) + + EE.copy(C) + EE.mul(D) + EE.mul(b) + F.copy(B) + F.sub(EE) + G.copy(B) + G.add(EE) + + if CURVE_A == 1 { + EE.copy(D) + EE.sub(C) + } + C.add(D) + + B.copy(E.x) + B.add(E.y) + D.copy(Q.x) + D.add(Q.y) + B.norm() + D.norm() + B.mul(D) + B.sub(C) + B.norm() + F.norm() + B.mul(F) + E.x.copy(A) + E.x.mul(B) + G.norm() + if CURVE_A == 1 { + EE.norm() + C.copy(EE) + C.mul(G) + } + if CURVE_A == -1 { + C.norm() + C.mul(G) + } + E.y.copy(A) + E.y.mul(C) + E.z.copy(F) + E.z.mul(G) + } + return +} + +/* Differential Add for Montgomery curves. this+=Q where W is this-Q and is affine. */ +func (E *ECP) dadd(Q *ECP, W *ECP) { + A := NewFPcopy(E.x) + B := NewFPcopy(E.x) + C := NewFPcopy(Q.x) + D := NewFPcopy(Q.x) + DA := NewFP() + CB := NewFP() + + A.add(E.z) + B.sub(E.z) + + C.add(Q.z) + D.sub(Q.z) + A.norm() + D.norm() + + DA.copy(D) + DA.mul(A) + C.norm() + B.norm() + + CB.copy(C) + CB.mul(B) + + A.copy(DA) + A.add(CB) + A.norm() + A.sqr() + B.copy(DA) + B.sub(CB) + B.norm() + B.sqr() + + E.x.copy(A) + E.z.copy(W.x) + E.z.mul(B) + +} + +/* this-=Q */ +func (E *ECP) Sub(Q *ECP) { + NQ := NewECP() + NQ.Copy(Q) + NQ.neg() + E.Add(NQ) +} + +/* constant time multiply by small integer of length bts - use ladder */ +func (E *ECP) pinmul(e int32, bts int32) *ECP { + if CURVETYPE == MONTGOMERY { + return E.mul(NewBIGint(int(e))) + } else { + P := NewECP() + R0 := NewECP() + R1 := NewECP() + R1.Copy(E) + + for i := bts - 1; i >= 0; i-- { + b := int((e >> uint32(i)) & 1) + P.Copy(R1) + P.Add(R0) + R0.cswap(R1, b) + R1.Copy(P) + R0.dbl() + R0.cswap(R1, b) + } + P.Copy(R0) + P.Affine() + return P + } +} + +/* return e.this */ + +func (E *ECP) mul(e *BIG) *ECP { + if e.iszilch() || E.Is_infinity() { + return NewECP() + } + P := NewECP() + if CURVETYPE == MONTGOMERY { + /* use Ladder */ + D := NewECP() + R0 := NewECP() + R0.Copy(E) + R1 := NewECP() + R1.Copy(E) + R1.dbl() + D.Copy(E) + D.Affine() + nb := e.nbits() + for i := nb - 2; i >= 0; i-- { + b := int(e.bit(i)) + P.Copy(R1) + P.dadd(R0, D) + R0.cswap(R1, b) + R1.Copy(P) + R0.dbl() + R0.cswap(R1, b) + } + P.Copy(R0) + } else { + // fixed size windows + mt := NewBIG() + t := NewBIG() + Q := NewECP() + C := NewECP() + + var W []*ECP + var w [1 + (NLEN*int(BASEBITS)+3)/4]int8 + + Q.Copy(E) + Q.dbl() + + W = append(W, NewECP()) + W[0].Copy(E) + + for i := 1; i < 8; i++ { + W = append(W, NewECP()) + W[i].Copy(W[i-1]) + W[i].Add(Q) + } + + // make exponent odd - add 2P if even, P if odd + t.copy(e) + s := int(t.parity()) + t.inc(1) + t.norm() + ns := int(t.parity()) + mt.copy(t) + mt.inc(1) + mt.norm() + t.cmove(mt, s) + Q.cmove(E, ns) + C.Copy(Q) + + nb := 1 + (t.nbits()+3)/4 + + // convert exponent to signed 4-bit window + for i := 0; i < nb; i++ { + w[i] = int8(t.lastbits(5) - 16) + t.dec(int(w[i])) + t.norm() + t.fshr(4) + } + w[nb] = int8(t.lastbits(5)) + + P.Copy(W[(int(w[nb])-1)/2]) + for i := nb - 1; i >= 0; i-- { + Q.selector(W, int32(w[i])) + P.dbl() + P.dbl() + P.dbl() + P.dbl() + P.Add(Q) + } + P.Sub(C) /* apply correction */ + } + P.Affine() + return P +} + +/* Public version */ +func (E *ECP) Mul(e *BIG) *ECP { + return E.mul(e) +} + +/* Return e.this+f.Q */ + +func (E *ECP) Mul2(e *BIG, Q *ECP, f *BIG) *ECP { + te := NewBIG() + tf := NewBIG() + mt := NewBIG() + S := NewECP() + T := NewECP() + C := NewECP() + var W []*ECP + var w [1 + (NLEN*int(BASEBITS)+1)/2]int8 + + te.copy(e) + tf.copy(f) + + // precompute table + for i := 0; i < 8; i++ { + W = append(W, NewECP()) + } + W[1].Copy(E) + W[1].Sub(Q) + W[2].Copy(E) + W[2].Add(Q) + S.Copy(Q) + S.dbl() + W[0].Copy(W[1]) + W[0].Sub(S) + W[3].Copy(W[2]) + W[3].Add(S) + T.Copy(E) + T.dbl() + W[5].Copy(W[1]) + W[5].Add(T) + W[6].Copy(W[2]) + W[6].Add(T) + W[4].Copy(W[5]) + W[4].Sub(S) + W[7].Copy(W[6]) + W[7].Add(S) + + // if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to correction + + s := int(te.parity()) + te.inc(1) + te.norm() + ns := int(te.parity()) + mt.copy(te) + mt.inc(1) + mt.norm() + te.cmove(mt, s) + T.cmove(E, ns) + C.Copy(T) + + s = int(tf.parity()) + tf.inc(1) + tf.norm() + ns = int(tf.parity()) + mt.copy(tf) + mt.inc(1) + mt.norm() + tf.cmove(mt, s) + S.cmove(Q, ns) + C.Add(S) + + mt.copy(te) + mt.add(tf) + mt.norm() + nb := 1 + (mt.nbits()+1)/2 + + // convert exponent to signed 2-bit window + for i := 0; i < nb; i++ { + a := (te.lastbits(3) - 4) + te.dec(int(a)) + te.norm() + te.fshr(2) + b := (tf.lastbits(3) - 4) + tf.dec(int(b)) + tf.norm() + tf.fshr(2) + w[i] = int8(4*a + b) + } + w[nb] = int8(4*te.lastbits(3) + tf.lastbits(3)) + S.Copy(W[(w[nb]-1)/2]) + + for i := nb - 1; i >= 0; i-- { + T.selector(W, int32(w[i])) + S.dbl() + S.dbl() + S.Add(T) + } + S.Sub(C) /* apply correction */ + S.Affine() + return S +} + +func (E *ECP) cfp() { + cf := CURVE_Cof_I + if cf == 1 { + return + } + if cf == 4 { + E.dbl() + E.dbl() + return + } + if cf == 8 { + E.dbl() + E.dbl() + E.dbl() + return + } + c := NewBIGints(CURVE_Cof) + E.Copy(E.mul(c)) +} + +func ECP_mapit(h []byte) *ECP { + q := NewBIGints(Modulus) + x := FromBytes(h[:]) + x.Mod(q) + var P *ECP + + for true { + for true { + if CURVETYPE != MONTGOMERY { + P = NewECPbigint(x, 0) + } else { + P = NewECPbig(x) + } + x.inc(1) + x.norm() + if !P.Is_infinity() { + break + } + } + P.cfp() + if !P.Is_infinity() { + break + } + } + + return P +} + +func ECP_generator() *ECP { + var G *ECP + + gx := NewBIGints(CURVE_Gx) + if CURVETYPE != MONTGOMERY { + gy := NewBIGints(CURVE_Gy) + G = NewECPbigs(gx, gy) + } else { + G = NewECPbig(gx) + } + return G +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP.go index 54f514879f9..3ead4d24f0c 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -22,8 +24,6 @@ under the License. package FP256BN - - //const NOT_SPECIAL int = 0 //const PSEUDO_MERSENNE int = 1 //const MONTGOMERY_FRIENDLY int = 2 diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12.go index 3485ff0a696..c65de175d46 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -22,12 +24,10 @@ under the License. package FP256BN - - type FP12 struct { - a *FP4 - b *FP4 - c *FP4 + a *FP4 + b *FP4 + c *FP4 stype int } @@ -37,7 +37,7 @@ func NewFP12() *FP12 { F.a = NewFP4() F.b = NewFP4() F.c = NewFP4() - F.stype=FP_ZERO + F.stype = FP_ZERO return F } @@ -46,7 +46,7 @@ func NewFP12fp4(d *FP4) *FP12 { F.a = NewFP4copy(d) F.b = NewFP4() F.c = NewFP4() - F.stype=FP_SPARSER + F.stype = FP_SPARSER return F } @@ -55,10 +55,10 @@ func NewFP12int(d int) *FP12 { F.a = NewFP4int(d) F.b = NewFP4() F.c = NewFP4() - if d==1 { - F.stype=FP_ONE + if d == 1 { + F.stype = FP_ONE } else { - F.stype=FP_SPARSER + F.stype = FP_SPARSER } return F } @@ -68,7 +68,7 @@ func NewFP12fp4s(d *FP4, e *FP4, f *FP4) *FP12 { F.a = NewFP4copy(d) F.b = NewFP4copy(e) F.c = NewFP4copy(f) - F.stype=FP_DENSE + F.stype = FP_DENSE return F } @@ -77,7 +77,7 @@ func NewFP12copy(x *FP12) *FP12 { F.a = NewFP4copy(x.a) F.b = NewFP4copy(x.b) F.c = NewFP4copy(x.c) - F.stype=x.stype + F.stype = x.stype return F } @@ -105,8 +105,8 @@ func (F *FP12) cmove(g *FP12, d int) { F.a.cmove(g.a, d) F.b.cmove(g.b, d) F.c.cmove(g.c, d) - d=^(d-1) - F.stype^=(F.stype^g.stype)&d + d = ^(d - 1) + F.stype ^= (F.stype ^ g.stype) & d } /* Constant time select from pre-computed table */ @@ -162,7 +162,7 @@ func (F *FP12) Copy(x *FP12) { F.a.copy(x.a) F.b.copy(x.b) F.c.copy(x.c) - F.stype=x.stype + F.stype = x.stype } /* set this=1 */ @@ -170,7 +170,7 @@ func (F *FP12) one() { F.a.one() F.b.zero() F.c.zero() - F.stype=FP_ONE + F.stype = FP_ONE } /* set this=0 */ @@ -178,7 +178,7 @@ func (F *FP12) zero() { F.a.zero() F.b.zero() F.c.zero() - F.stype=FP_ZERO + F.stype = FP_ZERO } /* this=conj(this) */ @@ -227,13 +227,13 @@ func (F *FP12) usqr() { F.b.add(B) F.c.add(C) F.reduce() - F.stype=FP_DENSE + F.stype = FP_DENSE } /* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ func (F *FP12) sqr() { - if F.stype==FP_ONE { + if F.stype == FP_ONE { return } @@ -272,10 +272,10 @@ func (F *FP12) sqr() { F.b.copy(C) F.b.add(D) F.c.add(A) - if F.stype==FP_SPARSER { - F.stype=FP_SPARSE + if F.stype == FP_SPARSER { + F.stype = FP_SPARSE } else { - F.stype=FP_DENSE + F.stype = FP_DENSE } F.norm() } @@ -344,39 +344,38 @@ func (F *FP12) Mul(y *FP12) { z3.times_i() F.a.copy(z0) F.a.add(z3) - F.stype=FP_DENSE + F.stype = FP_DENSE F.norm() } - /* FP12 full multiplication w=w*y */ /* Supports sparse multiplicands */ /* Usually w is denser than y */ func (F *FP12) ssmul(y *FP12) { - if F.stype==FP_ONE { + if F.stype == FP_ONE { F.Copy(y) return } - if y.stype==FP_ONE { + if y.stype == FP_ONE { return } - if y.stype>=FP_SPARSE { - z0:=NewFP4copy(F.a) - z1:=NewFP4() - z2:=NewFP4() - z3:=NewFP4() + if y.stype >= FP_SPARSE { + z0 := NewFP4copy(F.a) + z1 := NewFP4() + z2 := NewFP4() + z3 := NewFP4() z0.mul(y.a) - if SEXTIC_TWIST==M_TYPE { - if y.stype==FP_SPARSE || F.stype==FP_SPARSE { + if SEXTIC_TWIST == M_TYPE { + if y.stype == FP_SPARSE || F.stype == FP_SPARSE { z2.getb().copy(F.b.getb()) z2.getb().mul(y.b.getb()) z2.geta().zero() - if y.stype!=FP_SPARSE { + if y.stype != FP_SPARSE { z2.geta().copy(F.b.getb()) z2.geta().mul(y.b.geta()) } - if F.stype!=FP_SPARSE { + if F.stype != FP_SPARSE { z2.geta().copy(F.b.geta()) z2.geta().mul(y.b.getb()) } @@ -389,42 +388,57 @@ func (F *FP12) ssmul(y *FP12) { z2.copy(F.b) z2.mul(y.b) } - t0:=NewFP4copy(F.a) - t1:=NewFP4copy(y.a) - t0.add(F.b); t0.norm(); - t1.add(y.b); t1.norm() - - z1.copy(t0); z1.mul(t1) - t0.copy(F.b); t0.add(F.c); t0.norm() - t1.copy(y.b); t1.add(y.c); t1.norm() - - z3.copy(t0); z3.mul(t1) - - t0.copy(z0); t0.neg() - t1.copy(z2); t1.neg() + t0 := NewFP4copy(F.a) + t1 := NewFP4copy(y.a) + t0.add(F.b) + t0.norm() + t1.add(y.b) + t1.norm() + + z1.copy(t0) + z1.mul(t1) + t0.copy(F.b) + t0.add(F.c) + t0.norm() + t1.copy(y.b) + t1.add(y.c) + t1.norm() + + z3.copy(t0) + z3.mul(t1) + + t0.copy(z0) + t0.neg() + t1.copy(z2) + t1.neg() z1.add(t0) - F.b.copy(z1); F.b.add(t1) + F.b.copy(z1) + F.b.add(t1) z3.add(t1) z2.add(t0) - t0.copy(F.a); t0.add(F.c); t0.norm() - t1.copy(y.a); t1.add(y.c); t1.norm() - + t0.copy(F.a) + t0.add(F.c) + t0.norm() + t1.copy(y.a) + t1.add(y.c) + t1.norm() + t0.mul(t1) z2.add(t0) - if SEXTIC_TWIST==D_TYPE { - if y.stype==FP_SPARSE || F.stype==FP_SPARSE { + if SEXTIC_TWIST == D_TYPE { + if y.stype == FP_SPARSE || F.stype == FP_SPARSE { t0.geta().copy(F.c.geta()) t0.geta().mul(y.c.geta()) t0.getb().zero() - if y.stype!=FP_SPARSE { + if y.stype != FP_SPARSE { t0.getb().copy(F.c.geta()) t0.getb().mul(y.c.getb()) } - if F.stype!=FP_SPARSE { + if F.stype != FP_SPARSE { t0.getb().copy(F.c.getb()) t0.getb().mul(y.c.geta()) } @@ -436,26 +450,29 @@ func (F *FP12) ssmul(y *FP12) { t0.copy(F.c) t0.mul(y.c) } - t1.copy(t0); t1.neg() + t1.copy(t0) + t1.neg() - F.c.copy(z2); F.c.add(t1) + F.c.copy(z2) + F.c.add(t1) z3.add(t1) t0.times_i() F.b.add(t0) z3.norm() z3.times_i() - F.a.copy(z0); F.a.add(z3); + F.a.copy(z0) + F.a.add(z3) } else { - if F.stype==FP_SPARSER { + if F.stype == FP_SPARSER { F.smul(y) return } - if SEXTIC_TWIST==D_TYPE { // dense by sparser - 13m - z0:=NewFP4copy(F.a) - z2:=NewFP4copy(F.b) - z3:=NewFP4copy(F.b) - t0:=NewFP4() - t1:=NewFP4copy(y.a) + if SEXTIC_TWIST == D_TYPE { // dense by sparser - 13m + z0 := NewFP4copy(F.a) + z2 := NewFP4copy(F.b) + z3 := NewFP4copy(F.b) + t0 := NewFP4() + t1 := NewFP4copy(y.a) z0.mul(y.a) z2.pmul(y.b.real()) F.b.add(F.a) @@ -468,8 +485,10 @@ func (F *FP12) ssmul(y *FP12) { z3.norm() z3.pmul(y.b.real()) - t0.copy(z0); t0.neg() - t1.copy(z2); t1.neg() + t0.copy(z0) + t0.neg() + t1.copy(z2) + t1.neg() F.b.add(t0) @@ -477,97 +496,121 @@ func (F *FP12) ssmul(y *FP12) { z3.add(t1) z2.add(t0) - t0.copy(F.a); t0.add(F.c); t0.norm() + t0.copy(F.a) + t0.add(F.c) + t0.norm() z3.norm() t0.mul(y.a) - F.c.copy(z2); F.c.add(t0) + F.c.copy(z2) + F.c.add(t0) z3.times_i() - F.a.copy(z0); F.a.add(z3) + F.a.copy(z0) + F.a.add(z3) } - if SEXTIC_TWIST==M_TYPE { - z0:=NewFP4copy(F.a) - z1:=NewFP4() - z2:=NewFP4() - z3:=NewFP4() - t0:=NewFP4copy(F.a) - t1:=NewFP4() - + if SEXTIC_TWIST == M_TYPE { + z0 := NewFP4copy(F.a) + z1 := NewFP4() + z2 := NewFP4() + z3 := NewFP4() + t0 := NewFP4copy(F.a) + t1 := NewFP4() + z0.mul(y.a) - t0.add(F.b); t0.norm() + t0.add(F.b) + t0.norm() - z1.copy(t0); z1.mul(y.a) - t0.copy(F.b); t0.add(F.c) + z1.copy(t0) + z1.mul(y.a) + t0.copy(F.b) + t0.add(F.c) t0.norm() z3.copy(t0) z3.pmul(y.c.getb()) z3.times_i() - t0.copy(z0); t0.neg() + t0.copy(z0) + t0.neg() z1.add(t0) F.b.copy(z1) z2.copy(t0) - t0.copy(F.a); t0.add(F.c); t0.norm() - t1.copy(y.a); t1.add(y.c); t1.norm() + t0.copy(F.a) + t0.add(F.c) + t0.norm() + t1.copy(y.a) + t1.add(y.c) + t1.norm() t0.mul(t1) z2.add(t0) t0.copy(F.c) - + t0.pmul(y.c.getb()) t0.times_i() - t1.copy(t0); t1.neg() + t1.copy(t0) + t1.neg() - F.c.copy(z2); F.c.add(t1) + F.c.copy(z2) + F.c.add(t1) z3.add(t1) t0.times_i() F.b.add(t0) z3.norm() z3.times_i() - F.a.copy(z0); F.a.add(z3) - } + F.a.copy(z0) + F.a.add(z3) + } } - F.stype=FP_DENSE + F.stype = FP_DENSE F.norm() } - /* Special case of multiplication arises from special form of ATE pairing line function */ func (F *FP12) smul(y *FP12) { - if SEXTIC_TWIST==D_TYPE { - w1:=NewFP2copy(F.a.geta()) - w2:=NewFP2copy(F.a.getb()) - w3:=NewFP2copy(F.b.geta()) + if SEXTIC_TWIST == D_TYPE { + w1 := NewFP2copy(F.a.geta()) + w2 := NewFP2copy(F.a.getb()) + w3 := NewFP2copy(F.b.geta()) w1.mul(y.a.geta()) w2.mul(y.a.getb()) w3.mul(y.b.geta()) - ta:=NewFP2copy(F.a.geta()) - tb:=NewFP2copy(y.a.geta()) - ta.add(F.a.getb()); ta.norm() - tb.add(y.a.getb()); tb.norm() - tc:=NewFP2copy(ta) - tc.mul(tb); - t:=NewFP2copy(w1) + ta := NewFP2copy(F.a.geta()) + tb := NewFP2copy(y.a.geta()) + ta.add(F.a.getb()) + ta.norm() + tb.add(y.a.getb()) + tb.norm() + tc := NewFP2copy(ta) + tc.mul(tb) + t := NewFP2copy(w1) t.add(w2) t.neg() tc.add(t) - ta.copy(F.a.geta()); ta.add(F.b.geta()); ta.norm() - tb.copy(y.a.geta()); tb.add(y.b.geta()); tb.norm() - td:=NewFP2copy(ta) + ta.copy(F.a.geta()) + ta.add(F.b.geta()) + ta.norm() + tb.copy(y.a.geta()) + tb.add(y.b.geta()) + tb.norm() + td := NewFP2copy(ta) td.mul(tb) t.copy(w1) t.add(w3) t.neg() td.add(t) - ta.copy(F.a.getb()); ta.add(F.b.geta()); ta.norm() - tb.copy(y.a.getb()); tb.add(y.b.geta()); tb.norm() - te:=NewFP2copy(ta) + ta.copy(F.a.getb()) + ta.add(F.b.geta()) + ta.norm() + tb.copy(y.a.getb()) + tb.add(y.b.geta()) + tb.norm() + te := NewFP2copy(ta) te.mul(tb) t.copy(w2) t.add(w3) @@ -577,44 +620,57 @@ func (F *FP12) smul(y *FP12) { w2.mul_ip() w1.add(w2) - F.a.geta().copy(w1); F.a.getb().copy(tc) - F.b.geta().copy(td); F.b.getb().copy(te) - F.c.geta().copy(w3); F.c.getb().zero() + F.a.geta().copy(w1) + F.a.getb().copy(tc) + F.b.geta().copy(td) + F.b.getb().copy(te) + F.c.geta().copy(w3) + F.c.getb().zero() F.a.norm() F.b.norm() } else { - w1:=NewFP2copy(F.a.geta()) - w2:=NewFP2copy(F.a.getb()) - w3:=NewFP2copy(F.c.getb()) + w1 := NewFP2copy(F.a.geta()) + w2 := NewFP2copy(F.a.getb()) + w3 := NewFP2copy(F.c.getb()) w1.mul(y.a.geta()) w2.mul(y.a.getb()) w3.mul(y.c.getb()) - ta:=NewFP2copy(F.a.geta()) - tb:=NewFP2copy(y.a.geta()) - ta.add(F.a.getb()); ta.norm() - tb.add(y.a.getb()); tb.norm() - tc:=NewFP2copy(ta) - tc.mul(tb); - t:=NewFP2copy(w1) + ta := NewFP2copy(F.a.geta()) + tb := NewFP2copy(y.a.geta()) + ta.add(F.a.getb()) + ta.norm() + tb.add(y.a.getb()) + tb.norm() + tc := NewFP2copy(ta) + tc.mul(tb) + t := NewFP2copy(w1) t.add(w2) t.neg() tc.add(t) - ta.copy(F.a.geta()); ta.add(F.c.getb()); ta.norm() - tb.copy(y.a.geta()); tb.add(y.c.getb()); tb.norm() - td:=NewFP2copy(ta) + ta.copy(F.a.geta()) + ta.add(F.c.getb()) + ta.norm() + tb.copy(y.a.geta()) + tb.add(y.c.getb()) + tb.norm() + td := NewFP2copy(ta) td.mul(tb) t.copy(w1) t.add(w3) t.neg() td.add(t) - ta.copy(F.a.getb()); ta.add(F.c.getb()); ta.norm() - tb.copy(y.a.getb()); tb.add(y.c.getb()); tb.norm() - te:=NewFP2copy(ta) + ta.copy(F.a.getb()) + ta.add(F.c.getb()) + ta.norm() + tb.copy(y.a.getb()) + tb.add(y.c.getb()) + tb.norm() + te := NewFP2copy(ta) te.mul(tb) t.copy(w2) t.add(w3) @@ -623,11 +679,13 @@ func (F *FP12) smul(y *FP12) { w2.mul_ip() w1.add(w2) - F.a.geta().copy(w1); F.a.getb().copy(tc) + F.a.geta().copy(w1) + F.a.getb().copy(tc) w3.mul_ip() w3.norm() - F.b.geta().zero(); F.b.getb().copy(w3) + F.b.geta().zero() + F.b.getb().copy(w3) te.norm() te.mul_ip() @@ -638,7 +696,7 @@ func (F *FP12) smul(y *FP12) { F.c.norm() } - F.stype=FP_SPARSE; + F.stype = FP_SPARSE } /* this=1/this */ @@ -686,7 +744,7 @@ func (F *FP12) Inverse() { F.b.mul(f3) F.c.copy(f2) F.c.mul(f3) - F.stype=FP_DENSE + F.stype = FP_DENSE } /* this=this^p using Frobenius */ @@ -703,7 +761,7 @@ func (F *FP12) frob(f *FP2) { F.b.pmul(f) F.c.pmul(f2) - F.stype=FP_DENSE + F.stype = FP_DENSE } /* trace function */ diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12_32.go new file mode 100644 index 00000000000..bb344c7b06a --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP12_32.go @@ -0,0 +1,1076 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* MiotCL Fp^12 functions */ +/* FP12 elements are of the form a+i.b+i^2.c */ + +package FP256BN + +type FP12 struct { + a *FP4 + b *FP4 + c *FP4 + stype int +} + +/* Constructors */ +func NewFP12() *FP12 { + F := new(FP12) + F.a = NewFP4() + F.b = NewFP4() + F.c = NewFP4() + F.stype = FP_ZERO + return F +} + +func NewFP12fp4(d *FP4) *FP12 { + F := new(FP12) + F.a = NewFP4copy(d) + F.b = NewFP4() + F.c = NewFP4() + F.stype = FP_SPARSER + return F +} + +func NewFP12int(d int) *FP12 { + F := new(FP12) + F.a = NewFP4int(d) + F.b = NewFP4() + F.c = NewFP4() + if d == 1 { + F.stype = FP_ONE + } else { + F.stype = FP_SPARSER + } + return F +} + +func NewFP12fp4s(d *FP4, e *FP4, f *FP4) *FP12 { + F := new(FP12) + F.a = NewFP4copy(d) + F.b = NewFP4copy(e) + F.c = NewFP4copy(f) + F.stype = FP_DENSE + return F +} + +func NewFP12copy(x *FP12) *FP12 { + F := new(FP12) + F.a = NewFP4copy(x.a) + F.b = NewFP4copy(x.b) + F.c = NewFP4copy(x.c) + F.stype = x.stype + return F +} + +/* reduce all components of this mod Modulus */ +func (F *FP12) reduce() { + F.a.reduce() + F.b.reduce() + F.c.reduce() +} + +/* normalise all components of this */ +func (F *FP12) norm() { + F.a.norm() + F.b.norm() + F.c.norm() +} + +/* test x==0 ? */ +func (F *FP12) iszilch() bool { + return (F.a.iszilch() && F.b.iszilch() && F.c.iszilch()) +} + +/* Conditional move */ +func (F *FP12) cmove(g *FP12, d int) { + F.a.cmove(g.a, d) + F.b.cmove(g.b, d) + F.c.cmove(g.c, d) + d = ^(d - 1) + F.stype ^= (F.stype ^ g.stype) & d +} + +/* Constant time select from pre-computed table */ +func (F *FP12) selector(g []*FP12, b int32) { + + m := b >> 31 + babs := (b ^ m) - m + + babs = (babs - 1) / 2 + + F.cmove(g[0], teq(babs, 0)) // conditional move + F.cmove(g[1], teq(babs, 1)) + F.cmove(g[2], teq(babs, 2)) + F.cmove(g[3], teq(babs, 3)) + F.cmove(g[4], teq(babs, 4)) + F.cmove(g[5], teq(babs, 5)) + F.cmove(g[6], teq(babs, 6)) + F.cmove(g[7], teq(babs, 7)) + + invF := NewFP12copy(F) + invF.conj() + F.cmove(invF, int(m&1)) +} + +/* test x==1 ? */ +func (F *FP12) Isunity() bool { + one := NewFP4int(1) + return (F.a.Equals(one) && F.b.iszilch() && F.c.iszilch()) +} + +/* return 1 if x==y, else 0 */ +func (F *FP12) Equals(x *FP12) bool { + return (F.a.Equals(x.a) && F.b.Equals(x.b) && F.c.Equals(x.c)) +} + +/* extract a from this */ +func (F *FP12) geta() *FP4 { + return F.a +} + +/* extract b */ +func (F *FP12) getb() *FP4 { + return F.b +} + +/* extract c */ +func (F *FP12) getc() *FP4 { + return F.c +} + +/* copy this=x */ +func (F *FP12) Copy(x *FP12) { + F.a.copy(x.a) + F.b.copy(x.b) + F.c.copy(x.c) + F.stype = x.stype +} + +/* set this=1 */ +func (F *FP12) one() { + F.a.one() + F.b.zero() + F.c.zero() + F.stype = FP_ONE +} + +/* set this=0 */ +func (F *FP12) zero() { + F.a.zero() + F.b.zero() + F.c.zero() + F.stype = FP_ZERO +} + +/* this=conj(this) */ +func (F *FP12) conj() { + F.a.conj() + F.b.nconj() + F.c.conj() +} + +/* Granger-Scott Unitary Squaring */ +func (F *FP12) usqr() { + A := NewFP4copy(F.a) + B := NewFP4copy(F.c) + C := NewFP4copy(F.b) + D := NewFP4() + + F.a.sqr() + D.copy(F.a) + D.add(F.a) + F.a.add(D) + + F.a.norm() + A.nconj() + + A.add(A) + F.a.add(A) + B.sqr() + B.times_i() + + D.copy(B) + D.add(B) + B.add(D) + B.norm() + + C.sqr() + D.copy(C) + D.add(C) + C.add(D) + C.norm() + + F.b.conj() + F.b.add(F.b) + F.c.nconj() + + F.c.add(F.c) + F.b.add(B) + F.c.add(C) + F.reduce() + F.stype = FP_DENSE + +} + +/* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */ +func (F *FP12) sqr() { + if F.stype == FP_ONE { + return + } + + A := NewFP4copy(F.a) + B := NewFP4copy(F.b) + C := NewFP4copy(F.c) + D := NewFP4copy(F.a) + + A.sqr() + B.mul(F.c) + B.add(B) + B.norm() + C.sqr() + D.mul(F.b) + D.add(D) + + F.c.add(F.a) + F.c.add(F.b) + F.c.norm() + F.c.sqr() + + F.a.copy(A) + + A.add(B) + A.norm() + A.add(C) + A.add(D) + A.norm() + + A.neg() + B.times_i() + C.times_i() + + F.a.add(B) + + F.b.copy(C) + F.b.add(D) + F.c.add(A) + if F.stype == FP_SPARSER { + F.stype = FP_SPARSE + } else { + F.stype = FP_DENSE + } + F.norm() +} + +/* FP12 full multiplication this=this*y */ +func (F *FP12) Mul(y *FP12) { + z0 := NewFP4copy(F.a) + z1 := NewFP4() + z2 := NewFP4copy(F.b) + z3 := NewFP4() + t0 := NewFP4copy(F.a) + t1 := NewFP4copy(y.a) + + z0.mul(y.a) + z2.mul(y.b) + + t0.add(F.b) + t0.norm() + t1.add(y.b) + t1.norm() + + z1.copy(t0) + z1.mul(t1) + t0.copy(F.b) + t0.add(F.c) + t0.norm() + + t1.copy(y.b) + t1.add(y.c) + t1.norm() + z3.copy(t0) + z3.mul(t1) + + t0.copy(z0) + t0.neg() + t1.copy(z2) + t1.neg() + + z1.add(t0) + F.b.copy(z1) + F.b.add(t1) + + z3.add(t1) + z2.add(t0) + + t0.copy(F.a) + t0.add(F.c) + t0.norm() + t1.copy(y.a) + t1.add(y.c) + t1.norm() + t0.mul(t1) + z2.add(t0) + + t0.copy(F.c) + t0.mul(y.c) + t1.copy(t0) + t1.neg() + + F.c.copy(z2) + F.c.add(t1) + z3.add(t1) + t0.times_i() + F.b.add(t0) + z3.norm() + z3.times_i() + F.a.copy(z0) + F.a.add(z3) + F.stype = FP_DENSE + F.norm() +} + +/* FP12 full multiplication w=w*y */ +/* Supports sparse multiplicands */ +/* Usually w is denser than y */ +func (F *FP12) ssmul(y *FP12) { + if F.stype == FP_ONE { + F.Copy(y) + return + } + if y.stype == FP_ONE { + return + } + if y.stype >= FP_SPARSE { + z0 := NewFP4copy(F.a) + z1 := NewFP4() + z2 := NewFP4() + z3 := NewFP4() + z0.mul(y.a) + + if SEXTIC_TWIST == M_TYPE { + if y.stype == FP_SPARSE || F.stype == FP_SPARSE { + z2.getb().copy(F.b.getb()) + z2.getb().mul(y.b.getb()) + z2.geta().zero() + if y.stype != FP_SPARSE { + z2.geta().copy(F.b.getb()) + z2.geta().mul(y.b.geta()) + } + if F.stype != FP_SPARSE { + z2.geta().copy(F.b.geta()) + z2.geta().mul(y.b.getb()) + } + z2.times_i() + } else { + z2.copy(F.b) + z2.mul(y.b) + } + } else { + z2.copy(F.b) + z2.mul(y.b) + } + t0 := NewFP4copy(F.a) + t1 := NewFP4copy(y.a) + t0.add(F.b) + t0.norm() + t1.add(y.b) + t1.norm() + + z1.copy(t0) + z1.mul(t1) + t0.copy(F.b) + t0.add(F.c) + t0.norm() + t1.copy(y.b) + t1.add(y.c) + t1.norm() + + z3.copy(t0) + z3.mul(t1) + + t0.copy(z0) + t0.neg() + t1.copy(z2) + t1.neg() + + z1.add(t0) + F.b.copy(z1) + F.b.add(t1) + + z3.add(t1) + z2.add(t0) + + t0.copy(F.a) + t0.add(F.c) + t0.norm() + t1.copy(y.a) + t1.add(y.c) + t1.norm() + + t0.mul(t1) + z2.add(t0) + + if SEXTIC_TWIST == D_TYPE { + if y.stype == FP_SPARSE || F.stype == FP_SPARSE { + t0.geta().copy(F.c.geta()) + t0.geta().mul(y.c.geta()) + t0.getb().zero() + if y.stype != FP_SPARSE { + t0.getb().copy(F.c.geta()) + t0.getb().mul(y.c.getb()) + } + if F.stype != FP_SPARSE { + t0.getb().copy(F.c.getb()) + t0.getb().mul(y.c.geta()) + } + } else { + t0.copy(F.c) + t0.mul(y.c) + } + } else { + t0.copy(F.c) + t0.mul(y.c) + } + t1.copy(t0) + t1.neg() + + F.c.copy(z2) + F.c.add(t1) + z3.add(t1) + t0.times_i() + F.b.add(t0) + z3.norm() + z3.times_i() + F.a.copy(z0) + F.a.add(z3) + } else { + if F.stype == FP_SPARSER { + F.smul(y) + return + } + if SEXTIC_TWIST == D_TYPE { // dense by sparser - 13m + z0 := NewFP4copy(F.a) + z2 := NewFP4copy(F.b) + z3 := NewFP4copy(F.b) + t0 := NewFP4() + t1 := NewFP4copy(y.a) + z0.mul(y.a) + z2.pmul(y.b.real()) + F.b.add(F.a) + t1.real().add(y.b.real()) + + t1.norm() + F.b.norm() + F.b.mul(t1) + z3.add(F.c) + z3.norm() + z3.pmul(y.b.real()) + + t0.copy(z0) + t0.neg() + t1.copy(z2) + t1.neg() + + F.b.add(t0) + + F.b.add(t1) + z3.add(t1) + z2.add(t0) + + t0.copy(F.a) + t0.add(F.c) + t0.norm() + z3.norm() + t0.mul(y.a) + F.c.copy(z2) + F.c.add(t0) + + z3.times_i() + F.a.copy(z0) + F.a.add(z3) + } + if SEXTIC_TWIST == M_TYPE { + z0 := NewFP4copy(F.a) + z1 := NewFP4() + z2 := NewFP4() + z3 := NewFP4() + t0 := NewFP4copy(F.a) + t1 := NewFP4() + + z0.mul(y.a) + t0.add(F.b) + t0.norm() + + z1.copy(t0) + z1.mul(y.a) + t0.copy(F.b) + t0.add(F.c) + t0.norm() + + z3.copy(t0) + z3.pmul(y.c.getb()) + z3.times_i() + + t0.copy(z0) + t0.neg() + z1.add(t0) + F.b.copy(z1) + z2.copy(t0) + + t0.copy(F.a) + t0.add(F.c) + t0.norm() + t1.copy(y.a) + t1.add(y.c) + t1.norm() + + t0.mul(t1) + z2.add(t0) + t0.copy(F.c) + + t0.pmul(y.c.getb()) + t0.times_i() + t1.copy(t0) + t1.neg() + + F.c.copy(z2) + F.c.add(t1) + z3.add(t1) + t0.times_i() + F.b.add(t0) + z3.norm() + z3.times_i() + F.a.copy(z0) + F.a.add(z3) + } + } + F.stype = FP_DENSE + F.norm() +} + +/* Special case of multiplication arises from special form of ATE pairing line function */ +func (F *FP12) smul(y *FP12) { + if SEXTIC_TWIST == D_TYPE { + w1 := NewFP2copy(F.a.geta()) + w2 := NewFP2copy(F.a.getb()) + w3 := NewFP2copy(F.b.geta()) + + w1.mul(y.a.geta()) + w2.mul(y.a.getb()) + w3.mul(y.b.geta()) + + ta := NewFP2copy(F.a.geta()) + tb := NewFP2copy(y.a.geta()) + ta.add(F.a.getb()) + ta.norm() + tb.add(y.a.getb()) + tb.norm() + tc := NewFP2copy(ta) + tc.mul(tb) + t := NewFP2copy(w1) + t.add(w2) + t.neg() + tc.add(t) + + ta.copy(F.a.geta()) + ta.add(F.b.geta()) + ta.norm() + tb.copy(y.a.geta()) + tb.add(y.b.geta()) + tb.norm() + td := NewFP2copy(ta) + td.mul(tb) + t.copy(w1) + t.add(w3) + t.neg() + td.add(t) + + ta.copy(F.a.getb()) + ta.add(F.b.geta()) + ta.norm() + tb.copy(y.a.getb()) + tb.add(y.b.geta()) + tb.norm() + te := NewFP2copy(ta) + te.mul(tb) + t.copy(w2) + t.add(w3) + t.neg() + te.add(t) + + w2.mul_ip() + w1.add(w2) + + F.a.geta().copy(w1) + F.a.getb().copy(tc) + F.b.geta().copy(td) + F.b.getb().copy(te) + F.c.geta().copy(w3) + F.c.getb().zero() + + F.a.norm() + F.b.norm() + } else { + w1 := NewFP2copy(F.a.geta()) + w2 := NewFP2copy(F.a.getb()) + w3 := NewFP2copy(F.c.getb()) + + w1.mul(y.a.geta()) + w2.mul(y.a.getb()) + w3.mul(y.c.getb()) + + ta := NewFP2copy(F.a.geta()) + tb := NewFP2copy(y.a.geta()) + ta.add(F.a.getb()) + ta.norm() + tb.add(y.a.getb()) + tb.norm() + tc := NewFP2copy(ta) + tc.mul(tb) + t := NewFP2copy(w1) + t.add(w2) + t.neg() + tc.add(t) + + ta.copy(F.a.geta()) + ta.add(F.c.getb()) + ta.norm() + tb.copy(y.a.geta()) + tb.add(y.c.getb()) + tb.norm() + td := NewFP2copy(ta) + td.mul(tb) + t.copy(w1) + t.add(w3) + t.neg() + td.add(t) + + ta.copy(F.a.getb()) + ta.add(F.c.getb()) + ta.norm() + tb.copy(y.a.getb()) + tb.add(y.c.getb()) + tb.norm() + te := NewFP2copy(ta) + te.mul(tb) + t.copy(w2) + t.add(w3) + t.neg() + te.add(t) + + w2.mul_ip() + w1.add(w2) + F.a.geta().copy(w1) + F.a.getb().copy(tc) + + w3.mul_ip() + w3.norm() + F.b.geta().zero() + F.b.getb().copy(w3) + + te.norm() + te.mul_ip() + F.c.geta().copy(te) + F.c.getb().copy(td) + + F.a.norm() + F.c.norm() + + } + F.stype = FP_SPARSE +} + +/* this=1/this */ +func (F *FP12) Inverse() { + f0 := NewFP4copy(F.a) + f1 := NewFP4copy(F.b) + f2 := NewFP4copy(F.a) + f3 := NewFP4() + + F.norm() + f0.sqr() + f1.mul(F.c) + f1.times_i() + f0.sub(f1) + f0.norm() + + f1.copy(F.c) + f1.sqr() + f1.times_i() + f2.mul(F.b) + f1.sub(f2) + f1.norm() + + f2.copy(F.b) + f2.sqr() + f3.copy(F.a) + f3.mul(F.c) + f2.sub(f3) + f2.norm() + + f3.copy(F.b) + f3.mul(f2) + f3.times_i() + F.a.mul(f0) + f3.add(F.a) + F.c.mul(f1) + F.c.times_i() + + f3.add(F.c) + f3.norm() + f3.inverse() + F.a.copy(f0) + F.a.mul(f3) + F.b.copy(f1) + F.b.mul(f3) + F.c.copy(f2) + F.c.mul(f3) + F.stype = FP_DENSE +} + +/* this=this^p using Frobenius */ +func (F *FP12) frob(f *FP2) { + f2 := NewFP2copy(f) + f3 := NewFP2copy(f) + + f2.sqr() + f3.mul(f2) + + F.a.frob(f3) + F.b.frob(f3) + F.c.frob(f3) + + F.b.pmul(f) + F.c.pmul(f2) + F.stype = FP_DENSE +} + +/* trace function */ +func (F *FP12) trace() *FP4 { + t := NewFP4() + t.copy(F.a) + t.imul(3) + t.reduce() + return t +} + +/* convert from byte array to FP12 */ +func FP12_fromBytes(w []byte) *FP12 { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + + for i := 0; i < MB; i++ { + t[i] = w[i] + } + a := FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+MB] + } + b := FromBytes(t[:]) + c := NewFP2bigs(a, b) + + for i := 0; i < MB; i++ { + t[i] = w[i+2*MB] + } + a = FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+3*MB] + } + b = FromBytes(t[:]) + d := NewFP2bigs(a, b) + + e := NewFP4fp2s(c, d) + + for i := 0; i < MB; i++ { + t[i] = w[i+4*MB] + } + a = FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+5*MB] + } + b = FromBytes(t[:]) + c = NewFP2bigs(a, b) + + for i := 0; i < MB; i++ { + t[i] = w[i+6*MB] + } + a = FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+7*MB] + } + b = FromBytes(t[:]) + d = NewFP2bigs(a, b) + + f := NewFP4fp2s(c, d) + + for i := 0; i < MB; i++ { + t[i] = w[i+8*MB] + } + a = FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+9*MB] + } + b = FromBytes(t[:]) + + c = NewFP2bigs(a, b) + + for i := 0; i < MB; i++ { + t[i] = w[i+10*MB] + } + a = FromBytes(t[:]) + for i := 0; i < MB; i++ { + t[i] = w[i+11*MB] + } + b = FromBytes(t[:]) + d = NewFP2bigs(a, b) + + g := NewFP4fp2s(c, d) + + return NewFP12fp4s(e, f, g) +} + +/* convert this to byte array */ +func (F *FP12) ToBytes(w []byte) { + var t [int(MODBYTES)]byte + MB := int(MODBYTES) + F.a.geta().GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i] = t[i] + } + F.a.geta().GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+MB] = t[i] + } + F.a.getb().GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+2*MB] = t[i] + } + F.a.getb().GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+3*MB] = t[i] + } + + F.b.geta().GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+4*MB] = t[i] + } + F.b.geta().GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+5*MB] = t[i] + } + F.b.getb().GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+6*MB] = t[i] + } + F.b.getb().GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+7*MB] = t[i] + } + + F.c.geta().GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+8*MB] = t[i] + } + F.c.geta().GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+9*MB] = t[i] + } + F.c.getb().GetA().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+10*MB] = t[i] + } + F.c.getb().GetB().ToBytes(t[:]) + for i := 0; i < MB; i++ { + w[i+11*MB] = t[i] + } +} + +/* convert to hex string */ +func (F *FP12) ToString() string { + return ("[" + F.a.toString() + "," + F.b.toString() + "," + F.c.toString() + "]") +} + +/* this=this^e */ +func (F *FP12) Pow(e *BIG) *FP12 { + //F.norm() + e1 := NewBIGcopy(e) + e1.norm() + e3 := NewBIGcopy(e1) + e3.pmul(3) + e3.norm() + sf := NewFP12copy(F) + sf.norm() + w := NewFP12copy(sf) + + nb := e3.nbits() + for i := nb - 2; i >= 1; i-- { + w.usqr() + bt := e3.bit(i) - e1.bit(i) + if bt == 1 { + w.Mul(sf) + } + if bt == -1 { + sf.conj() + w.Mul(sf) + sf.conj() + } + } + w.reduce() + return w +} + +/* constant time powering by small integer of max length bts */ +func (F *FP12) pinpow(e int, bts int) { + var R []*FP12 + R = append(R, NewFP12int(1)) + R = append(R, NewFP12copy(F)) + + for i := bts - 1; i >= 0; i-- { + b := (e >> uint(i)) & 1 + R[1-b].Mul(R[b]) + R[b].usqr() + } + F.Copy(R[0]) +} + +/* Fast compressed FP4 power of unitary FP12 */ +func (F *FP12) Compow(e *BIG, r *BIG) *FP4 { + q := NewBIGints(Modulus) + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + + m := NewBIGcopy(q) + m.Mod(r) + + a := NewBIGcopy(e) + a.Mod(m) + + b := NewBIGcopy(e) + b.div(m) + + g1 := NewFP12copy(F) + c := g1.trace() + + if b.iszilch() { + c = c.xtr_pow(e) + return c + } + + g2 := NewFP12copy(F) + g2.frob(f) + cp := g2.trace() + + g1.conj() + g2.Mul(g1) + cpm1 := g2.trace() + g2.Mul(g1) + cpm2 := g2.trace() + + c = c.xtr_pow2(cp, cpm1, cpm2, a, b) + return c +} + +/* p=q0^u0.q1^u1.q2^u2.q3^u3 */ +// Bos & Costello https://eprint.iacr.org/2013/458.pdf +// Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf +// Side channel attack secure + +func pow4(q []*FP12, u []*BIG) *FP12 { + var g []*FP12 + var w [NLEN*int(BASEBITS) + 1]int8 + var s [NLEN*int(BASEBITS) + 1]int8 + var t []*BIG + r := NewFP12() + p := NewFP12() + mt := NewBIGint(0) + + for i := 0; i < 4; i++ { + t = append(t, NewBIGcopy(u[i])) + } + + g = append(g, NewFP12copy(q[0])) // q[0] + g = append(g, NewFP12copy(g[0])) + g[1].Mul(q[1]) // q[0].q[1] + g = append(g, NewFP12copy(g[0])) + g[2].Mul(q[2]) // q[0].q[2] + g = append(g, NewFP12copy(g[1])) + g[3].Mul(q[2]) // q[0].q[1].q[2] + g = append(g, NewFP12copy(g[0])) + g[4].Mul(q[3]) // q[0].q[3] + g = append(g, NewFP12copy(g[1])) + g[5].Mul(q[3]) // q[0].q[1].q[3] + g = append(g, NewFP12copy(g[2])) + g[6].Mul(q[3]) // q[0].q[2].q[3] + g = append(g, NewFP12copy(g[3])) + g[7].Mul(q[3]) // q[0].q[1].q[2].q[3] + + // Make it odd + pb := 1 - t[0].parity() + t[0].inc(pb) + // t[0].norm(); + + // Number of bits + mt.zero() + for i := 0; i < 4; i++ { + t[i].norm() + mt.or(t[i]) + } + + nb := 1 + mt.nbits() + + // Sign pivot + s[nb-1] = 1 + for i := 0; i < nb-1; i++ { + t[0].fshr(1) + s[i] = 2*int8(t[0].parity()) - 1 + } + + // Recoded exponent + for i := 0; i < nb; i++ { + w[i] = 0 + k := 1 + for j := 1; j < 4; j++ { + bt := s[i] * int8(t[j].parity()) + t[j].fshr(1) + t[j].dec(int(bt) >> 1) + t[j].norm() + w[i] += bt * int8(k) + k *= 2 + } + } + + // Main loop + p.selector(g, int32(2*w[nb-1]+1)) + for i := nb - 2; i >= 0; i-- { + p.usqr() + r.selector(g, int32(2*w[i]+s[i])) + p.Mul(r) + } + + // apply correction + r.Copy(q[0]) + r.conj() + r.Mul(p) + p.cmove(r, pb) + + p.reduce() + return p +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2.go index ddb48eb5348..018c4c90cd9 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -23,8 +25,6 @@ under the License. package FP256BN - - type FP2 struct { a *FP b *FP diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2_32.go new file mode 100644 index 00000000000..aebc012d70a --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP2_32.go @@ -0,0 +1,366 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* Finite Field arithmetic Fp^2 functions */ + +/* FP2 elements are of the form a+ib, where i is sqrt(-1) */ + +package FP256BN + +type FP2 struct { + a *FP + b *FP +} + +/* Constructors */ +func NewFP2() *FP2 { + F := new(FP2) + F.a = NewFP() + F.b = NewFP() + return F +} + +func NewFP2int(a int) *FP2 { + F := new(FP2) + F.a = NewFPint(a) + F.b = NewFP() + return F +} + +func NewFP2copy(x *FP2) *FP2 { + F := new(FP2) + F.a = NewFPcopy(x.a) + F.b = NewFPcopy(x.b) + return F +} + +func NewFP2fps(c *FP, d *FP) *FP2 { + F := new(FP2) + F.a = NewFPcopy(c) + F.b = NewFPcopy(d) + return F +} + +func NewFP2bigs(c *BIG, d *BIG) *FP2 { + F := new(FP2) + F.a = NewFPbig(c) + F.b = NewFPbig(d) + return F +} + +func NewFP2fp(c *FP) *FP2 { + F := new(FP2) + F.a = NewFPcopy(c) + F.b = NewFP() + return F +} + +func NewFP2big(c *BIG) *FP2 { + F := new(FP2) + F.a = NewFPbig(c) + F.b = NewFP() + return F +} + +/* reduce components mod Modulus */ +func (F *FP2) reduce() { + F.a.reduce() + F.b.reduce() +} + +/* normalise components of w */ +func (F *FP2) norm() { + F.a.norm() + F.b.norm() +} + +/* test this=0 ? */ +func (F *FP2) iszilch() bool { + return (F.a.iszilch() && F.b.iszilch()) +} + +func (F *FP2) cmove(g *FP2, d int) { + F.a.cmove(g.a, d) + F.b.cmove(g.b, d) +} + +/* test this=1 ? */ +func (F *FP2) isunity() bool { + one := NewFPint(1) + return (F.a.Equals(one) && F.b.iszilch()) +} + +/* test this=x */ +func (F *FP2) Equals(x *FP2) bool { + return (F.a.Equals(x.a) && F.b.Equals(x.b)) +} + +/* extract a */ +func (F *FP2) GetA() *BIG { + return F.a.redc() +} + +/* extract b */ +func (F *FP2) GetB() *BIG { + return F.b.redc() +} + +/* copy this=x */ +func (F *FP2) copy(x *FP2) { + F.a.copy(x.a) + F.b.copy(x.b) +} + +/* set this=0 */ +func (F *FP2) zero() { + F.a.zero() + F.b.zero() +} + +/* set this=1 */ +func (F *FP2) one() { + F.a.one() + F.b.zero() +} + +/* negate this mod Modulus */ +func (F *FP2) neg() { + m := NewFPcopy(F.a) + t := NewFP() + + m.add(F.b) + m.neg() + t.copy(m) + t.add(F.b) + F.b.copy(m) + F.b.add(F.a) + F.a.copy(t) +} + +/* set to a-ib */ +func (F *FP2) conj() { + F.b.neg() + F.b.norm() +} + +/* this+=a */ +func (F *FP2) add(x *FP2) { + F.a.add(x.a) + F.b.add(x.b) +} + +/* this-=a */ +func (F *FP2) sub(x *FP2) { + m := NewFP2copy(x) + m.neg() + F.add(m) +} + +/* this-=a */ +func (F *FP2) rsub(x *FP2) { + F.neg() + F.add(x) +} + +/* this*=s, where s is an FP */ +func (F *FP2) pmul(s *FP) { + F.a.mul(s) + F.b.mul(s) +} + +/* this*=i, where i is an int */ +func (F *FP2) imul(c int) { + F.a.imul(c) + F.b.imul(c) +} + +/* this*=this */ +func (F *FP2) sqr() { + w1 := NewFPcopy(F.a) + w3 := NewFPcopy(F.a) + mb := NewFPcopy(F.b) + w1.add(F.b) + + w3.add(F.a) + w3.norm() + F.b.mul(w3) + + mb.neg() + F.a.add(mb) + + w1.norm() + F.a.norm() + + F.a.mul(w1) +} + +/* this*=y */ +/* Now using Lazy reduction */ +func (F *FP2) mul(y *FP2) { + + if int64(F.a.XES+F.b.XES)*int64(y.a.XES+y.b.XES) > int64(FEXCESS) { + if F.a.XES > 1 { + F.a.reduce() + } + if F.b.XES > 1 { + F.b.reduce() + } + } + + pR := NewDBIG() + C := NewBIGcopy(F.a.x) + D := NewBIGcopy(y.a.x) + p := NewBIGints(Modulus) + + pR.ucopy(p) + + A := mul(F.a.x, y.a.x) + B := mul(F.b.x, y.b.x) + + C.add(F.b.x) + C.norm() + D.add(y.b.x) + D.norm() + + E := mul(C, D) + FF := NewDBIGcopy(A) + FF.add(B) + B.rsub(pR) + + A.add(B) + A.norm() + E.sub(FF) + E.norm() + + F.a.x.copy(mod(A)) + F.a.XES = 3 + F.b.x.copy(mod(E)) + F.b.XES = 2 + +} + +/* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */ +/* returns true if this is QR */ +func (F *FP2) sqrt() bool { + if F.iszilch() { + return true + } + w1 := NewFPcopy(F.b) + w2 := NewFPcopy(F.a) + w1.sqr() + w2.sqr() + w1.add(w2) + if w1.jacobi() != 1 { + F.zero() + return false + } + w1 = w1.sqrt() + w2.copy(F.a) + w2.add(w1) + w2.norm() + w2.div2() + if w2.jacobi() != 1 { + w2.copy(F.a) + w2.sub(w1) + w2.norm() + w2.div2() + if w2.jacobi() != 1 { + F.zero() + return false + } + } + w2 = w2.sqrt() + F.a.copy(w2) + w2.add(w2) + w2.inverse() + F.b.mul(w2) + return true +} + +/* output to hex string */ +func (F *FP2) toString() string { + return ("[" + F.a.toString() + "," + F.b.toString() + "]") +} + +/* this=1/this */ +func (F *FP2) inverse() { + F.norm() + w1 := NewFPcopy(F.a) + w2 := NewFPcopy(F.b) + + w1.sqr() + w2.sqr() + w1.add(w2) + w1.inverse() + F.a.mul(w1) + w1.neg() + w1.norm() + F.b.mul(w1) +} + +/* this/=2 */ +func (F *FP2) div2() { + F.a.div2() + F.b.div2() +} + +/* this*=sqrt(-1) */ +func (F *FP2) times_i() { + z := NewFPcopy(F.a) + F.a.copy(F.b) + F.a.neg() + F.b.copy(z) +} + +/* w*=(1+sqrt(-1)) */ +/* where X*2-(1+sqrt(-1)) is irreducible for FP4, assumes p=3 mod 8 */ +func (F *FP2) mul_ip() { + t := NewFP2copy(F) + z := NewFPcopy(F.a) + F.a.copy(F.b) + F.a.neg() + F.b.copy(z) + F.add(t) +} + +func (F *FP2) div_ip2() { + t := NewFP2() + F.norm() + t.a.copy(F.a) + t.a.add(F.b) + t.b.copy(F.b) + t.b.sub(F.a) + F.copy(t) + F.norm() +} + +/* w/=(1+sqrt(-1)) */ +func (F *FP2) div_ip() { + t := NewFP2() + F.norm() + t.a.copy(F.a) + t.a.add(F.b) + t.b.copy(F.b) + t.b.sub(F.a) + F.copy(t) + F.norm() + F.div2() +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4.go index 4a08ada6c2f..06b7656978f 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -23,8 +25,6 @@ under the License. package FP256BN - - type FP4 struct { a *FP2 b *FP2 diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4_32.go new file mode 100644 index 00000000000..210f6af38f5 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP4_32.go @@ -0,0 +1,646 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* Finite Field arithmetic Fp^4 functions */ + +/* FP4 elements are of the form a+ib, where i is sqrt(-1+sqrt(-1)) */ + +package FP256BN + +type FP4 struct { + a *FP2 + b *FP2 +} + +/* Constructors */ +func NewFP4() *FP4 { + F := new(FP4) + F.a = NewFP2() + F.b = NewFP2() + return F +} + +func NewFP4int(a int) *FP4 { + F := new(FP4) + F.a = NewFP2int(a) + F.b = NewFP2() + return F +} + +func NewFP4copy(x *FP4) *FP4 { + F := new(FP4) + F.a = NewFP2copy(x.a) + F.b = NewFP2copy(x.b) + return F +} + +func NewFP4fp2s(c *FP2, d *FP2) *FP4 { + F := new(FP4) + F.a = NewFP2copy(c) + F.b = NewFP2copy(d) + return F +} + +func NewFP4fp2(c *FP2) *FP4 { + F := new(FP4) + F.a = NewFP2copy(c) + F.b = NewFP2() + return F +} + +/* reduce all components of this mod Modulus */ +func (F *FP4) reduce() { + F.a.reduce() + F.b.reduce() +} + +/* normalise all components of this mod Modulus */ +func (F *FP4) norm() { + F.a.norm() + F.b.norm() +} + +/* test this==0 ? */ +func (F *FP4) iszilch() bool { + return F.a.iszilch() && F.b.iszilch() +} + +/* Conditional move */ +func (F *FP4) cmove(g *FP4, d int) { + F.a.cmove(g.a, d) + F.b.cmove(g.b, d) +} + +/* test this==1 ? */ +func (F *FP4) isunity() bool { + one := NewFP2int(1) + return F.a.Equals(one) && F.b.iszilch() +} + +/* test is w real? That is in a+ib test b is zero */ +func (F *FP4) isreal() bool { + return F.b.iszilch() +} + +/* extract real part a */ +func (F *FP4) real() *FP2 { + return F.a +} + +func (F *FP4) geta() *FP2 { + return F.a +} + +/* extract imaginary part b */ +func (F *FP4) getb() *FP2 { + return F.b +} + +/* test this=x? */ +func (F *FP4) Equals(x *FP4) bool { + return (F.a.Equals(x.a) && F.b.Equals(x.b)) +} + +/* copy this=x */ +func (F *FP4) copy(x *FP4) { + F.a.copy(x.a) + F.b.copy(x.b) +} + +/* set this=0 */ +func (F *FP4) zero() { + F.a.zero() + F.b.zero() +} + +/* set this=1 */ +func (F *FP4) one() { + F.a.one() + F.b.zero() +} + +/* set this=-this */ +func (F *FP4) neg() { + F.norm() + m := NewFP2copy(F.a) + t := NewFP2() + m.add(F.b) + m.neg() + t.copy(m) + t.add(F.b) + F.b.copy(m) + F.b.add(F.a) + F.a.copy(t) + F.norm() +} + +/* this=conjugate(this) */ +func (F *FP4) conj() { + F.b.neg() + F.norm() +} + +/* this=-conjugate(this) */ +func (F *FP4) nconj() { + F.a.neg() + F.norm() +} + +/* this+=x */ +func (F *FP4) add(x *FP4) { + F.a.add(x.a) + F.b.add(x.b) +} + +/* this-=x */ +func (F *FP4) sub(x *FP4) { + m := NewFP4copy(x) + m.neg() + F.add(m) +} + +/* this-=x */ +func (F *FP4) rsub(x *FP4) { + F.neg() + F.add(x) +} + +/* this*=s where s is FP2 */ +func (F *FP4) pmul(s *FP2) { + F.a.mul(s) + F.b.mul(s) +} + +/* this*=s where s is FP2 */ +func (F *FP4) qmul(s *FP) { + F.a.pmul(s) + F.b.pmul(s) +} + +/* this*=c where c is int */ +func (F *FP4) imul(c int) { + F.a.imul(c) + F.b.imul(c) +} + +/* this*=this */ +func (F *FP4) sqr() { + t1 := NewFP2copy(F.a) + t2 := NewFP2copy(F.b) + t3 := NewFP2copy(F.a) + + t3.mul(F.b) + t1.add(F.b) + t2.mul_ip() + + t2.add(F.a) + + t1.norm() + t2.norm() + + F.a.copy(t1) + + F.a.mul(t2) + + t2.copy(t3) + t2.mul_ip() + t2.add(t3) + t2.norm() + t2.neg() + F.a.add(t2) + + F.b.copy(t3) + F.b.add(t3) + + F.norm() +} + +/* this*=y */ +func (F *FP4) mul(y *FP4) { + t1 := NewFP2copy(F.a) + t2 := NewFP2copy(F.b) + t3 := NewFP2() + t4 := NewFP2copy(F.b) + + t1.mul(y.a) + t2.mul(y.b) + t3.copy(y.b) + t3.add(y.a) + t4.add(F.a) + + t3.norm() + t4.norm() + + t4.mul(t3) + + t3.copy(t1) + t3.neg() + t4.add(t3) + t4.norm() + + t3.copy(t2) + t3.neg() + F.b.copy(t4) + F.b.add(t3) + + t2.mul_ip() + F.a.copy(t2) + F.a.add(t1) + + F.norm() +} + +/* convert this to hex string */ +func (F *FP4) toString() string { + return ("[" + F.a.toString() + "," + F.b.toString() + "]") +} + +/* this=1/this */ +func (F *FP4) inverse() { + t1 := NewFP2copy(F.a) + t2 := NewFP2copy(F.b) + + t1.sqr() + t2.sqr() + t2.mul_ip() + t2.norm() + t1.sub(t2) + t1.inverse() + F.a.mul(t1) + t1.neg() + t1.norm() + F.b.mul(t1) +} + +/* this*=i where i = sqrt(-1+sqrt(-1)) */ +func (F *FP4) times_i() { + s := NewFP2copy(F.b) + t := NewFP2copy(F.b) + s.times_i() + t.add(s) + F.b.copy(F.a) + F.a.copy(t) + F.norm() +} + +/* this=this^p using Frobenius */ +func (F *FP4) frob(f *FP2) { + F.a.conj() + F.b.conj() + F.b.mul(f) +} + +/* this=this^e */ +func (F *FP4) pow(e *BIG) *FP4 { + w := NewFP4copy(F) + w.norm() + z := NewBIGcopy(e) + r := NewFP4int(1) + z.norm() + for true { + bt := z.parity() + z.fshr(1) + if bt == 1 { + r.mul(w) + } + if z.iszilch() { + break + } + w.sqr() + } + r.reduce() + return r +} + +/* XTR xtr_a function */ +func (F *FP4) xtr_A(w *FP4, y *FP4, z *FP4) { + r := NewFP4copy(w) + t := NewFP4copy(w) + r.sub(y) + r.norm() + r.pmul(F.a) + t.add(y) + t.norm() + t.pmul(F.b) + t.times_i() + + F.copy(r) + F.add(t) + F.add(z) + + F.norm() +} + +/* XTR xtr_d function */ +func (F *FP4) xtr_D() { + w := NewFP4copy(F) + F.sqr() + w.conj() + w.add(w) + w.norm() + F.sub(w) + F.reduce() +} + +/* r=x^n using XTR method on traces of FP12s */ +func (F *FP4) xtr_pow(n *BIG) *FP4 { + a := NewFP4int(3) + b := NewFP4copy(F) + c := NewFP4copy(b) + c.xtr_D() + t := NewFP4() + r := NewFP4() + sf := NewFP4copy(F) + sf.norm() + + par := n.parity() + v := NewBIGcopy(n) + v.norm() + v.fshr(1) + if par == 0 { + v.dec(1) + v.norm() + } + + nb := v.nbits() + for i := nb - 1; i >= 0; i-- { + if v.bit(i) != 1 { + t.copy(b) + sf.conj() + c.conj() + b.xtr_A(a, sf, c) + sf.conj() + c.copy(t) + c.xtr_D() + a.xtr_D() + } else { + t.copy(a) + t.conj() + a.copy(b) + a.xtr_D() + b.xtr_A(c, sf, t) + c.xtr_D() + } + } + if par == 0 { + r.copy(c) + } else { + r.copy(b) + } + r.reduce() + return r +} + +/* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */ +func (F *FP4) xtr_pow2(ck *FP4, ckml *FP4, ckm2l *FP4, a *BIG, b *BIG) *FP4 { + + e := NewBIGcopy(a) + d := NewBIGcopy(b) + w := NewBIGint(0) + e.norm() + d.norm() + + cu := NewFP4copy(ck) // can probably be passed in w/o copying + cv := NewFP4copy(F) + cumv := NewFP4copy(ckml) + cum2v := NewFP4copy(ckm2l) + r := NewFP4() + t := NewFP4() + + f2 := 0 + for d.parity() == 0 && e.parity() == 0 { + d.fshr(1) + e.fshr(1) + f2++ + } + + for Comp(d, e) != 0 { + if Comp(d, e) > 0 { + w.copy(e) + w.imul(4) + w.norm() + if Comp(d, w) <= 0 { + w.copy(d) + d.copy(e) + e.rsub(w) + e.norm() + + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cum2v.copy(cumv) + cum2v.conj() + cumv.copy(cv) + cv.copy(cu) + cu.copy(t) + } else { + if d.parity() == 0 { + d.fshr(1) + r.copy(cum2v) + r.conj() + t.copy(cumv) + t.xtr_A(cu, cv, r) + cum2v.copy(cumv) + cum2v.xtr_D() + cumv.copy(t) + cu.xtr_D() + } else { + if e.parity() == 1 { + d.sub(e) + d.norm() + d.fshr(1) + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cu.xtr_D() + cum2v.copy(cv) + cum2v.xtr_D() + cum2v.conj() + cv.copy(t) + } else { + w.copy(d) + d.copy(e) + d.fshr(1) + e.copy(w) + t.copy(cumv) + t.xtr_D() + cumv.copy(cum2v) + cumv.conj() + cum2v.copy(t) + cum2v.conj() + t.copy(cv) + t.xtr_D() + cv.copy(cu) + cu.copy(t) + } + } + } + } + if Comp(d, e) < 0 { + w.copy(d) + w.imul(4) + w.norm() + if Comp(e, w) <= 0 { + e.sub(d) + e.norm() + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cum2v.copy(cumv) + cumv.copy(cu) + cu.copy(t) + } else { + if e.parity() == 0 { + w.copy(d) + d.copy(e) + d.fshr(1) + e.copy(w) + t.copy(cumv) + t.xtr_D() + cumv.copy(cum2v) + cumv.conj() + cum2v.copy(t) + cum2v.conj() + t.copy(cv) + t.xtr_D() + cv.copy(cu) + cu.copy(t) + } else { + if d.parity() == 1 { + w.copy(e) + e.copy(d) + w.sub(d) + w.norm() + d.copy(w) + d.fshr(1) + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cumv.conj() + cum2v.copy(cu) + cum2v.xtr_D() + cum2v.conj() + cu.copy(cv) + cu.xtr_D() + cv.copy(t) + } else { + d.fshr(1) + r.copy(cum2v) + r.conj() + t.copy(cumv) + t.xtr_A(cu, cv, r) + cum2v.copy(cumv) + cum2v.xtr_D() + cumv.copy(t) + cu.xtr_D() + } + } + } + } + } + r.copy(cv) + r.xtr_A(cu, cumv, cum2v) + for i := 0; i < f2; i++ { + r.xtr_D() + } + r = r.xtr_pow(d) + return r +} + +/* this/=2 */ +func (F *FP4) div2() { + F.a.div2() + F.b.div2() +} + +func (F *FP4) div_i() { + u := NewFP2copy(F.a) + v := NewFP2copy(F.b) + u.div_ip() + F.a.copy(v) + F.b.copy(u) +} + +func (F *FP4) div_2i() { + u := NewFP2copy(F.a) + v := NewFP2copy(F.b) + u.div_ip2() + v.add(v) + v.norm() + F.a.copy(v) + F.b.copy(u) +} + +/* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */ +/* returns true if this is QR */ +func (F *FP4) sqrt() bool { + if F.iszilch() { + return true + } + + a := NewFP2copy(F.a) + s := NewFP2copy(F.b) + t := NewFP2copy(F.a) + + if s.iszilch() { + if t.sqrt() { + F.a.copy(t) + F.b.zero() + } else { + t.div_ip() + t.sqrt() + F.b.copy(t) + F.a.zero() + } + return true + } + s.sqr() + a.sqr() + s.mul_ip() + s.norm() + a.sub(s) + + s.copy(a) + if !s.sqrt() { + return false + } + + a.copy(t) + a.add(s) + a.norm() + a.div2() + + if !a.sqrt() { + a.copy(t) + a.sub(s) + a.norm() + a.div2() + if !a.sqrt() { + return false + } + } + t.copy(F.b) + s.copy(a) + s.add(a) + s.inverse() + + t.mul(s) + F.a.copy(a) + F.b.copy(t) + + return true +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP_32.go new file mode 100644 index 00000000000..e8abecdb886 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/FP_32.go @@ -0,0 +1,600 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* Finite Field arithmetic */ +/* CLINT mod p functions */ + +package FP256BN + +//const NOT_SPECIAL int = 0 +//const PSEUDO_MERSENNE int = 1 +//const MONTGOMERY_FRIENDLY int = 2 +//const GENERALISED_MERSENNE int = 3 + +//const MODBITS uint = @NBT@ /* Number of bits in Modulus */ +//const MOD8 uint = @M8@ /* Modulus mod 8 */ +//const MODTYPE int = @MT@ //NOT_SPECIAL +//const FEXCESS int32=((int32(1)<<@SH@)-1) + +//const OMASK Chunk = ((Chunk(-1)) << (MODBITS % BASEBITS)) +//const TBITS uint = MODBITS % BASEBITS // Number of active bits in top word +//const TMASK Chunk = (Chunk(1) << TBITS) - 1 + +type FP struct { + x *BIG + XES int32 +} + +/* Constructors */ +func NewFP() *FP { + F := new(FP) + F.x = NewBIG() + F.XES = 1 + return F +} + +func NewFPint(a int) *FP { + F := new(FP) + F.x = NewBIGint(a) + F.nres() + return F +} + +func NewFPbig(a *BIG) *FP { + F := new(FP) + F.x = NewBIGcopy(a) + F.nres() + return F +} + +func NewFPcopy(a *FP) *FP { + F := new(FP) + F.x = NewBIGcopy(a.x) + F.XES = a.XES + return F +} + +func (F *FP) toString() string { + F.reduce() + return F.redc().ToString() +} + +/* convert to Montgomery n-residue form */ +func (F *FP) nres() { + if MODTYPE != PSEUDO_MERSENNE && MODTYPE != GENERALISED_MERSENNE { + r := NewBIGints(R2modp) + d := mul(F.x, r) + F.x.copy(mod(d)) + F.XES = 2 + } else { + F.XES = 1 + } +} + +/* convert back to regular form */ +func (F *FP) redc() *BIG { + if MODTYPE != PSEUDO_MERSENNE && MODTYPE != GENERALISED_MERSENNE { + d := NewDBIGscopy(F.x) + return mod(d) + } else { + r := NewBIGcopy(F.x) + return r + } +} + +/* reduce a DBIG to a BIG using the appropriate form of the modulus */ + +func mod(d *DBIG) *BIG { + if MODTYPE == PSEUDO_MERSENNE { + t := d.split(MODBITS) + b := NewBIGdcopy(d) + + v := t.pmul(int(MConst)) + + t.add(b) + t.norm() + + tw := t.w[NLEN-1] + t.w[NLEN-1] &= TMASK + t.w[0] += (MConst * ((tw >> TBITS) + (v << (BASEBITS - TBITS)))) + + t.norm() + return t + } + if MODTYPE == MONTGOMERY_FRIENDLY { + for i := 0; i < NLEN; i++ { + top, bot := muladd(d.w[i], MConst-1, d.w[i], d.w[NLEN+i-1]) + d.w[NLEN+i-1] = bot + d.w[NLEN+i] += top + } + b := NewBIG() + + for i := 0; i < NLEN; i++ { + b.w[i] = d.w[NLEN+i] + } + b.norm() + return b + } + + if MODTYPE == GENERALISED_MERSENNE { // GoldiLocks only + t := d.split(MODBITS) + b := NewBIGdcopy(d) + b.add(t) + dd := NewDBIGscopy(t) + dd.shl(MODBITS / 2) + + tt := dd.split(MODBITS) + lo := NewBIGdcopy(dd) + b.add(tt) + b.add(lo) + b.norm() + tt.shl(MODBITS / 2) + b.add(tt) + + carry := b.w[NLEN-1] >> TBITS + b.w[NLEN-1] &= TMASK + b.w[0] += carry + + b.w[224/BASEBITS] += carry << (224 % BASEBITS) + b.norm() + return b + } + + if MODTYPE == NOT_SPECIAL { + md := NewBIGints(Modulus) + return monty(md, MConst, d) + } + return NewBIG() +} + +// find appoximation to quotient of a/m +// Out by at most 2. +// Note that MAXXES is bounded to be 2-bits less than half a word +func quo(n *BIG, m *BIG) int { + var num Chunk + var den Chunk + hb := uint(CHUNK) / 2 + if TBITS < hb { + sh := hb - TBITS + num = (n.w[NLEN-1] << sh) | (n.w[NLEN-2] >> (BASEBITS - sh)) + den = (m.w[NLEN-1] << sh) | (m.w[NLEN-2] >> (BASEBITS - sh)) + + } else { + num = n.w[NLEN-1] + den = m.w[NLEN-1] + } + return int(num / (den + 1)) +} + +/* reduce this mod Modulus */ +func (F *FP) reduce() { + m := NewBIGints(Modulus) + r := NewBIGints(Modulus) + var sb uint + F.x.norm() + + if F.XES > 16 { + q := quo(F.x, m) + carry := r.pmul(q) + r.w[NLEN-1] += carry << BASEBITS + F.x.sub(r) + F.x.norm() + sb = 2 + } else { + sb = logb2(uint32(F.XES - 1)) + } + + m.fshl(sb) + for sb > 0 { + sr := ssn(r, F.x, m) + F.x.cmove(r, 1-sr) + sb -= 1 + } + + F.XES = 1 +} + +/* test this=0? */ +func (F *FP) iszilch() bool { + W := NewFPcopy(F) + W.reduce() + return W.x.iszilch() +} + +/* copy from FP b */ +func (F *FP) copy(b *FP) { + F.x.copy(b.x) + F.XES = b.XES +} + +/* set this=0 */ +func (F *FP) zero() { + F.x.zero() + F.XES = 1 +} + +/* set this=1 */ +func (F *FP) one() { + F.x.one() + F.nres() +} + +/* normalise this */ +func (F *FP) norm() { + F.x.norm() +} + +/* swap FPs depending on d */ +func (F *FP) cswap(b *FP, d int) { + c := int32(d) + c = ^(c - 1) + t := c & (F.XES ^ b.XES) + F.XES ^= t + b.XES ^= t + F.x.cswap(b.x, d) +} + +/* copy FPs depending on d */ +func (F *FP) cmove(b *FP, d int) { + F.x.cmove(b.x, d) + c := int32(-d) + F.XES ^= (F.XES ^ b.XES) & c +} + +/* this*=b mod Modulus */ +func (F *FP) mul(b *FP) { + + if int64(F.XES)*int64(b.XES) > int64(FEXCESS) { + F.reduce() + } + + d := mul(F.x, b.x) + F.x.copy(mod(d)) + F.XES = 2 +} + +/* this = -this mod Modulus */ +func (F *FP) neg() { + m := NewBIGints(Modulus) + sb := logb2(uint32(F.XES - 1)) + + m.fshl(sb) + F.x.rsub(m) + + F.XES = (1 << sb) + 1 + if F.XES > FEXCESS { + F.reduce() + } +} + +/* this*=c mod Modulus, where c is a small int */ +func (F *FP) imul(c int) { + // F.norm() + s := false + if c < 0 { + c = -c + s = true + } + + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + d := F.x.pxmul(c) + F.x.copy(mod(d)) + F.XES = 2 + } else { + if F.XES*int32(c) <= FEXCESS { + F.x.pmul(c) + F.XES *= int32(c) + } else { + n := NewFPint(c) + F.mul(n) + } + } + if s { + F.neg() + F.norm() + } +} + +/* this*=this mod Modulus */ +func (F *FP) sqr() { + if int64(F.XES)*int64(F.XES) > int64(FEXCESS) { + F.reduce() + } + d := sqr(F.x) + F.x.copy(mod(d)) + F.XES = 2 +} + +/* this+=b */ +func (F *FP) add(b *FP) { + F.x.add(b.x) + F.XES += b.XES + if F.XES > FEXCESS { + F.reduce() + } +} + +/* this-=b */ +func (F *FP) sub(b *FP) { + n := NewFPcopy(b) + n.neg() + F.add(n) +} + +func (F *FP) rsub(b *FP) { + F.neg() + F.add(b) +} + +/* this/=2 mod Modulus */ +func (F *FP) div2() { + if F.x.parity() == 0 { + F.x.fshr(1) + } else { + p := NewBIGints(Modulus) + F.x.add(p) + F.x.norm() + F.x.fshr(1) + } +} + +// See https://eprint.iacr.org/2018/1038 +// return this^(p-3)/4 or this^(p-5)/8 +func (F *FP) fpow() *FP { + ac := [11]int{1, 2, 3, 6, 12, 15, 30, 60, 120, 240, 255} + var xp []*FP + // phase 1 + xp = append(xp, NewFPcopy(F)) + xp = append(xp, NewFPcopy(F)) + xp[1].sqr() + xp = append(xp, NewFPcopy(xp[1])) + xp[2].mul(F) + xp = append(xp, NewFPcopy(xp[2])) + xp[3].sqr() + xp = append(xp, NewFPcopy(xp[3])) + xp[4].sqr() + xp = append(xp, NewFPcopy(xp[4])) + xp[5].mul(xp[2]) + xp = append(xp, NewFPcopy(xp[5])) + xp[6].sqr() + xp = append(xp, NewFPcopy(xp[6])) + xp[7].sqr() + xp = append(xp, NewFPcopy(xp[7])) + xp[8].sqr() + xp = append(xp, NewFPcopy(xp[8])) + xp[9].sqr() + xp = append(xp, NewFPcopy(xp[9])) + xp[10].mul(xp[5]) + var n, c int + + n = int(MODBITS) + if MODTYPE == GENERALISED_MERSENNE { // Goldilocks ONLY + n /= 2 + } + if MOD8 == 5 { + n -= 3 + c = (int(MConst) + 5) / 8 + } else { + n -= 2 + c = (int(MConst) + 3) / 4 + + } + + bw := 0 + w := 1 + for w < c { + w *= 2 + bw += 1 + } + k := w - c + + i := 10 + key := NewFP() + + if k != 0 { + for ac[i] > k { + i-- + } + key.copy(xp[i]) + k -= ac[i] + } + + for k != 0 { + i-- + if ac[i] > k { + continue + } + key.mul(xp[i]) + k -= ac[i] + } + // phase 2 + xp[1].copy(xp[2]) + xp[2].copy(xp[5]) + xp[3].copy(xp[10]) + + j := 3 + m := 8 + nw := n - bw + t := NewFP() + for 2*m < nw { + t.copy(xp[j]) + j++ + for i = 0; i < m; i++ { + t.sqr() + } + xp[j].copy(xp[j-1]) + xp[j].mul(t) + m *= 2 + } + lo := nw - m + r := NewFPcopy(xp[j]) + + for lo != 0 { + m /= 2 + j-- + if lo < m { + continue + } + lo -= m + t.copy(r) + for i = 0; i < m; i++ { + t.sqr() + } + r.copy(t) + r.mul(xp[j]) + } + // phase 3 + if bw != 0 { + for i = 0; i < bw; i++ { + r.sqr() + } + r.mul(key) + } + + if MODTYPE == GENERALISED_MERSENNE { // Goldilocks ONLY + key.copy(r) + r.sqr() + r.mul(F) + for i = 0; i < n+1; i++ { + r.sqr() + } + r.mul(key) + } + + return r +} + +/* this=1/this mod Modulus */ +func (F *FP) inverse() { + + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + y := F.fpow() + if MOD8 == 5 { + t := NewFPcopy(F) + t.sqr() + F.mul(t) + y.sqr() + } + y.sqr() + y.sqr() + F.mul(y) + } else { + m2 := NewBIGints(Modulus) + m2.dec(2) + m2.norm() + F.copy(F.pow(m2)) + } + +} + +/* return TRUE if this==a */ +func (F *FP) Equals(a *FP) bool { + f := NewFPcopy(F) + s := NewFPcopy(a) + + s.reduce() + f.reduce() + if Comp(s.x, f.x) == 0 { + return true + } + return false +} + +func (F *FP) pow(e *BIG) *FP { + var tb []*FP + var w [1 + (NLEN*int(BASEBITS)+3)/4]int8 + F.norm() + t := NewBIGcopy(e) + t.norm() + nb := 1 + (t.nbits()+3)/4 + + for i := 0; i < nb; i++ { + lsbs := t.lastbits(4) + t.dec(lsbs) + t.norm() + w[i] = int8(lsbs) + t.fshr(4) + } + tb = append(tb, NewFPint(1)) + tb = append(tb, NewFPcopy(F)) + for i := 2; i < 16; i++ { + tb = append(tb, NewFPcopy(tb[i-1])) + tb[i].mul(F) + } + r := NewFPcopy(tb[w[nb-1]]) + for i := nb - 2; i >= 0; i-- { + r.sqr() + r.sqr() + r.sqr() + r.sqr() + r.mul(tb[w[i]]) + } + r.reduce() + return r +} + +/* return sqrt(this) mod Modulus */ +func (F *FP) sqrt() *FP { + F.reduce() + if MOD8 == 5 { + var v *FP + i := NewFPcopy(F) + i.x.shl(1) + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + v = i.fpow() + } else { + b := NewBIGints(Modulus) + b.dec(5) + b.norm() + b.shr(3) + v = i.pow(b) + } + + i.mul(v) + i.mul(v) + i.x.dec(1) + r := NewFPcopy(F) + r.mul(v) + r.mul(i) + r.reduce() + return r + } else { + var r *FP + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + r = F.fpow() + r.mul(F) + } else { + b := NewBIGints(Modulus) + b.inc(1) + b.norm() + b.shr(2) + r = F.pow(b) + } + return r + } +} + +/* return jacobi symbol (this/Modulus) */ +func (F *FP) jacobi() int { + w := F.redc() + p := NewBIGints(Modulus) + return w.Jacobi(p) +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN.go index 41b41bc6700..8436961797f 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -21,10 +23,11 @@ under the License. package FP256BN -import "time" -import "github.com/hyperledger/fabric-amcl/amcl" - +import ( + "time" + "github.com/hyperledger/fabric-amcl/amcl" +) const MFS int = int(MODBYTES) const MGS int = int(MODBYTES) @@ -434,10 +437,10 @@ func MPIN_GET_SERVER_SECRET(S []byte, SST []byte) int { } /* - W=x*H(G); - if RNG == NULL then X is passed in - if RNG != NULL the X is passed out - if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve +W=x*H(G); +if RNG == NULL then X is passed in +if RNG != NULL the X is passed out +if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve */ func MPIN_GET_G1_MULTIPLE(rng *amcl.RAND, typ int, X []byte, G []byte, W []byte) int { var x *BIG diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN_32.go new file mode 100644 index 00000000000..f238113ff4f --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/MPIN_32.go @@ -0,0 +1,834 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* MPIN API Functions */ + +package FP256BN + +import "time" +import "github.com/hyperledger/fabric-amcl/amcl" + +const MFS int = int(MODBYTES) +const MGS int = int(MODBYTES) +const BAD_PARAMS int = -11 +const INVALID_POINT int = -14 +const WRONG_ORDER int = -18 +const BAD_PIN int = -19 + +/* Configure your PIN here */ + +const MAXPIN int32 = 10000 /* PIN less than this */ +const PBLEN int32 = 14 /* Number of bits in PIN */ +const TS int = 10 /* 10 for 4 digit PIN, 14 for 6-digit PIN - 2^TS/TS approx = sqrt(MAXPIN) */ +const TRAP int = 200 /* 200 for 4 digit PIN, 2000 for 6-digit PIN - approx 2*sqrt(MAXPIN) */ + +func mpin_hash(sha int, c *FP4, U *ECP) []byte { + var w [MFS]byte + var t [6 * MFS]byte + var h []byte + + c.geta().GetA().ToBytes(w[:]) + for i := 0; i < MFS; i++ { + t[i] = w[i] + } + c.geta().GetB().ToBytes(w[:]) + for i := MFS; i < 2*MFS; i++ { + t[i] = w[i-MFS] + } + c.getb().GetA().ToBytes(w[:]) + for i := 2 * MFS; i < 3*MFS; i++ { + t[i] = w[i-2*MFS] + } + c.getb().GetB().ToBytes(w[:]) + for i := 3 * MFS; i < 4*MFS; i++ { + t[i] = w[i-3*MFS] + } + + U.GetX().ToBytes(w[:]) + for i := 4 * MFS; i < 5*MFS; i++ { + t[i] = w[i-4*MFS] + } + U.GetY().ToBytes(w[:]) + for i := 5 * MFS; i < 6*MFS; i++ { + t[i] = w[i-5*MFS] + } + + if sha == amcl.SHA256 { + H := amcl.NewHASH256() + H.Process_array(t[:]) + h = H.Hash() + } + if sha == amcl.SHA384 { + H := amcl.NewHASH384() + H.Process_array(t[:]) + h = H.Hash() + } + if sha == amcl.SHA512 { + H := amcl.NewHASH512() + H.Process_array(t[:]) + h = H.Hash() + } + if h == nil { + return nil + } + R := make([]byte, AESKEY) + for i := 0; i < AESKEY; i++ { + R[i] = h[i] + } + return R +} + +/* Hash number (optional) and string to coordinate on curve */ + +func mhashit(sha int, n int32, ID []byte) []byte { + var R []byte + if sha == amcl.SHA256 { + H := amcl.NewHASH256() + if n != 0 { + H.Process_num(n) + } + H.Process_array(ID) + R = H.Hash() + } + if sha == amcl.SHA384 { + H := amcl.NewHASH384() + if n != 0 { + H.Process_num(n) + } + H.Process_array(ID) + R = H.Hash() + } + if sha == amcl.SHA512 { + H := amcl.NewHASH512() + if n != 0 { + H.Process_num(n) + } + H.Process_array(ID) + R = H.Hash() + } + if R == nil { + return nil + } + const RM int = int(MODBYTES) + var W [RM]byte + if sha >= RM { + for i := 0; i < RM; i++ { + W[i] = R[i] + } + } else { + for i := 0; i < sha; i++ { + W[i+RM-sha] = R[i] + } + for i := 0; i < RM-sha; i++ { + W[i] = 0 + } + } + + return W[:] +} + +/* return time in slots since epoch */ +func Today() int { + now := time.Now() + return int(now.Unix()) / (60 * 1440) +} + +/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* maps a random u to a point on the curve */ +func emap(u *BIG, cb int) *ECP { + var P *ECP + x := NewBIGcopy(u) + p := NewBIGints(Modulus) + x.Mod(p) + for true { + P = NewECPbigint(x, cb) + if !P.Is_infinity() { + break + } + x.inc(1) + x.norm() + } + return P +} + +/* returns u derived from P. Random value in range 1 to return value should then be added to u */ +func unmap(u *BIG, P *ECP) int { + s := P.GetS() + var R *ECP + r := 0 + x := P.GetX() + u.copy(x) + for true { + u.dec(1) + u.norm() + r++ + R = NewECPbigint(u, s) + if !R.Is_infinity() { + break + } + } + return r +} + +func MPIN_HASH_ID(sha int, ID []byte) []byte { + return mhashit(sha, 0, ID) +} + +/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */ +/* Note that u and v are indistinguisible from random strings */ +func MPIN_ENCODING(rng *amcl.RAND, E []byte) int { + var T [MFS]byte + + for i := 0; i < MFS; i++ { + T[i] = E[i+1] + } + u := FromBytes(T[:]) + for i := 0; i < MFS; i++ { + T[i] = E[i+MFS+1] + } + v := FromBytes(T[:]) + + P := NewECPbigs(u, v) + if P.Is_infinity() { + return INVALID_POINT + } + + p := NewBIGints(Modulus) + u = Randomnum(p, rng) + + su := int(rng.GetByte()) + su %= 2 + + W := emap(u, su) + P.Sub(W) + sv := P.GetS() + rn := unmap(v, P) + m := int(rng.GetByte()) + m %= rn + v.inc(m + 1) + E[0] = byte(su + 2*sv) + u.ToBytes(T[:]) + for i := 0; i < MFS; i++ { + E[i+1] = T[i] + } + v.ToBytes(T[:]) + for i := 0; i < MFS; i++ { + E[i+MFS+1] = T[i] + } + + return 0 +} + +func MPIN_DECODING(D []byte) int { + var T [MFS]byte + + if (D[0] & 0x04) != 0 { + return INVALID_POINT + } + + for i := 0; i < MFS; i++ { + T[i] = D[i+1] + } + u := FromBytes(T[:]) + for i := 0; i < MFS; i++ { + T[i] = D[i+MFS+1] + } + v := FromBytes(T[:]) + + su := int(D[0] & 1) + sv := int((D[0] >> 1) & 1) + W := emap(u, su) + P := emap(v, sv) + P.Add(W) + u = P.GetX() + v = P.GetY() + D[0] = 0x04 + u.ToBytes(T[:]) + for i := 0; i < MFS; i++ { + D[i+1] = T[i] + } + v.ToBytes(T[:]) + for i := 0; i < MFS; i++ { + D[i+MFS+1] = T[i] + } + + return 0 +} + +/* R=R1+R2 in group G1 */ +func MPIN_RECOMBINE_G1(R1 []byte, R2 []byte, R []byte) int { + P := ECP_fromBytes(R1) + Q := ECP_fromBytes(R2) + + if P.Is_infinity() || Q.Is_infinity() { + return INVALID_POINT + } + + P.Add(Q) + + P.ToBytes(R[:], false) + return 0 +} + +/* W=W1+W2 in group G2 */ +func MPIN_RECOMBINE_G2(W1 []byte, W2 []byte, W []byte) int { + P := ECP2_fromBytes(W1) + Q := ECP2_fromBytes(W2) + + if P.Is_infinity() || Q.Is_infinity() { + return INVALID_POINT + } + + P.Add(Q) + + P.ToBytes(W) + return 0 +} + +/* create random secret S */ +func MPIN_RANDOM_GENERATE(rng *amcl.RAND, S []byte) int { + r := NewBIGints(CURVE_Order) + s := Randomnum(r, rng) + s.ToBytes(S) + return 0 +} + +func MPIN_EXTRACT_PIN(sha int, CID []byte, pin int, TOKEN []byte) int { + return MPIN_EXTRACT_FACTOR(sha, CID, int32(pin)%MAXPIN, PBLEN, TOKEN) +} + +/* Extract factor from TOKEN for identity CID */ +func MPIN_EXTRACT_FACTOR(sha int, CID []byte, factor int32, facbits int32, TOKEN []byte) int { + P := ECP_fromBytes(TOKEN) + if P.Is_infinity() { + return INVALID_POINT + } + h := mhashit(sha, 0, CID) + R := ECP_mapit(h) + + R = R.pinmul(factor, facbits) + P.Sub(R) + + P.ToBytes(TOKEN, false) + + return 0 +} + +/* Restore factor to TOKEN for identity CID */ +func MPIN_RESTORE_FACTOR(sha int, CID []byte, factor int32, facbits int32, TOKEN []byte) int { + P := ECP_fromBytes(TOKEN) + if P.Is_infinity() { + return INVALID_POINT + } + h := mhashit(sha, 0, CID) + R := ECP_mapit(h) + + R = R.pinmul(factor, facbits) + P.Add(R) + + P.ToBytes(TOKEN, false) + + return 0 +} + +/* Implement step 2 on client side of MPin protocol */ +func MPIN_CLIENT_2(X []byte, Y []byte, SEC []byte) int { + r := NewBIGints(CURVE_Order) + P := ECP_fromBytes(SEC) + if P.Is_infinity() { + return INVALID_POINT + } + + px := FromBytes(X) + py := FromBytes(Y) + px.add(py) + px.Mod(r) + + P = G1mul(P, px) + P.neg() + P.ToBytes(SEC, false) + + return 0 +} + +/* Implement step 1 on client side of MPin protocol */ +func MPIN_CLIENT_1(sha int, date int, CLIENT_ID []byte, rng *amcl.RAND, X []byte, pin int, TOKEN []byte, SEC []byte, xID []byte, xCID []byte, PERMIT []byte) int { + r := NewBIGints(CURVE_Order) + + var x *BIG + if rng != nil { + x = Randomnum(r, rng) + x.ToBytes(X) + } else { + x = FromBytes(X) + } + + h := mhashit(sha, 0, CLIENT_ID) + P := ECP_mapit(h) + + T := ECP_fromBytes(TOKEN) + if T.Is_infinity() { + return INVALID_POINT + } + + W := P.pinmul(int32(pin)%MAXPIN, PBLEN) + T.Add(W) + if date != 0 { + W = ECP_fromBytes(PERMIT) + if W.Is_infinity() { + return INVALID_POINT + } + T.Add(W) + h = mhashit(sha, int32(date), h) + W = ECP_mapit(h) + if xID != nil { + P = G1mul(P, x) + P.ToBytes(xID, false) + W = G1mul(W, x) + P.Add(W) + } else { + P.Add(W) + P = G1mul(P, x) + } + if xCID != nil { + P.ToBytes(xCID, false) + } + } else { + if xID != nil { + P = G1mul(P, x) + P.ToBytes(xID, false) + } + } + + T.ToBytes(SEC, false) + return 0 +} + +/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ +func MPIN_GET_SERVER_SECRET(S []byte, SST []byte) int { + Q := ECP2_generator() + + s := FromBytes(S) + Q = G2mul(Q, s) + Q.ToBytes(SST) + return 0 +} + +/* +W=x*H(G); +if RNG == NULL then X is passed in +if RNG != NULL the X is passed out +if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve +*/ +func MPIN_GET_G1_MULTIPLE(rng *amcl.RAND, typ int, X []byte, G []byte, W []byte) int { + var x *BIG + r := NewBIGints(CURVE_Order) + if rng != nil { + x = Randomnum(r, rng) + x.ToBytes(X) + } else { + x = FromBytes(X) + } + var P *ECP + if typ == 0 { + P = ECP_fromBytes(G) + if P.Is_infinity() { + return INVALID_POINT + } + } else { + P = ECP_mapit(G) + } + + G1mul(P, x).ToBytes(W, false) + return 0 +} + +/* Client secret CST=S*H(CID) where CID is client ID and S is master secret */ +/* CID is hashed externally */ +func MPIN_GET_CLIENT_SECRET(S []byte, CID []byte, CST []byte) int { + return MPIN_GET_G1_MULTIPLE(nil, 1, S, CID, CST) +} + +/* Time Permit CTT=S*(date|H(CID)) where S is master secret */ +func MPIN_GET_CLIENT_PERMIT(sha, date int, S []byte, CID []byte, CTT []byte) int { + h := mhashit(sha, int32(date), CID) + P := ECP_mapit(h) + + s := FromBytes(S) + G1mul(P, s).ToBytes(CTT, false) + return 0 +} + +/* Outputs H(CID) and H(T|H(CID)) for time permits. If no time permits set HID=HTID */ +func MPIN_SERVER_1(sha int, date int, CID []byte, HID []byte, HTID []byte) { + h := mhashit(sha, 0, CID) + P := ECP_mapit(h) + + P.ToBytes(HID, false) + if date != 0 { + h = mhashit(sha, int32(date), h) + R := ECP_mapit(h) + P.Add(R) + P.ToBytes(HTID, false) + } +} + +/* Implement step 2 of MPin protocol on server side */ +func MPIN_SERVER_2(date int, HID []byte, HTID []byte, Y []byte, SST []byte, xID []byte, xCID []byte, mSEC []byte, E []byte, F []byte) int { + Q := ECP2_generator() + + sQ := ECP2_fromBytes(SST) + if sQ.Is_infinity() { + return INVALID_POINT + } + + var R *ECP + if date != 0 { + R = ECP_fromBytes(xCID) + } else { + if xID == nil { + return BAD_PARAMS + } + R = ECP_fromBytes(xID) + } + if R.Is_infinity() { + return INVALID_POINT + } + + y := FromBytes(Y) + var P *ECP + if date != 0 { + P = ECP_fromBytes(HTID) + } else { + if HID == nil { + return BAD_PARAMS + } + P = ECP_fromBytes(HID) + } + + if P.Is_infinity() { + return INVALID_POINT + } + + P = G1mul(P, y) + P.Add(R) + R = ECP_fromBytes(mSEC) + if R.Is_infinity() { + return INVALID_POINT + } + + var g *FP12 + + g = Ate2(Q, R, sQ, P) + g = Fexp(g) + + if !g.Isunity() { + if HID != nil && xID != nil && E != nil && F != nil { + g.ToBytes(E) + if date != 0 { + P = ECP_fromBytes(HID) + if P.Is_infinity() { + return INVALID_POINT + } + R = ECP_fromBytes(xID) + if R.Is_infinity() { + return INVALID_POINT + } + + P = G1mul(P, y) + P.Add(R) + //P.Affine() + } + g = Ate(Q, P) + g = Fexp(g) + g.ToBytes(F) + } + return BAD_PIN + } + + return 0 +} + +/* Pollards kangaroos used to return PIN error */ +func MPIN_KANGAROO(E []byte, F []byte) int { + ge := FP12_fromBytes(E) + gf := FP12_fromBytes(F) + var distance [TS]int + t := NewFP12copy(gf) + + var table []*FP12 + var i int + s := 1 + for m := 0; m < TS; m++ { + distance[m] = s + table = append(table, NewFP12copy(t)) + s *= 2 + t.usqr() + } + t.one() + dn := 0 + for j := 0; j < TRAP; j++ { + i = t.geta().geta().GetA().lastbits(20) % TS + t.Mul(table[i]) + dn += distance[i] + } + gf.Copy(t) + gf.conj() + steps := 0 + dm := 0 + res := 0 + for dm-dn < int(MAXPIN) { + steps++ + if steps > 4*TRAP { + break + } + i = ge.geta().geta().GetA().lastbits(20) % TS + ge.Mul(table[i]) + dm += distance[i] + if ge.Equals(t) { + res = dm - dn + break + } + if ge.Equals(gf) { + res = dn - dm + break + } + + } + if steps > 4*TRAP || dm-dn >= int(MAXPIN) { + res = 0 + } // Trap Failed - probable invalid token + return int(res) +} + +/* Functions to support M-Pin Full */ + +func MPIN_PRECOMPUTE(TOKEN []byte, CID []byte, G1 []byte, G2 []byte) int { + var P, T *ECP + var g *FP12 + + T = ECP_fromBytes(TOKEN) + if T.Is_infinity() { + return INVALID_POINT + } + + P = ECP_mapit(CID) + + Q := ECP2_generator() + + g = Ate(Q, T) + g = Fexp(g) + g.ToBytes(G1) + + g = Ate(Q, P) + g = Fexp(g) + g.ToBytes(G2) + + return 0 +} + +/* Hash the M-Pin transcript - new */ + +func MPIN_HASH_ALL(sha int, HID []byte, xID []byte, xCID []byte, SEC []byte, Y []byte, R []byte, W []byte) []byte { + tlen := 0 + var T [10*int(MODBYTES) + 4]byte + + for i := 0; i < len(HID); i++ { + T[i] = HID[i] + } + tlen += len(HID) + if xCID != nil { + for i := 0; i < len(xCID); i++ { + T[i+tlen] = xCID[i] + } + tlen += len(xCID) + } else { + for i := 0; i < len(xID); i++ { + T[i+tlen] = xID[i] + } + tlen += len(xID) + } + for i := 0; i < len(SEC); i++ { + T[i+tlen] = SEC[i] + } + tlen += len(SEC) + for i := 0; i < len(Y); i++ { + T[i+tlen] = Y[i] + } + tlen += len(Y) + for i := 0; i < len(R); i++ { + T[i+tlen] = R[i] + } + tlen += len(R) + for i := 0; i < len(W); i++ { + T[i+tlen] = W[i] + } + tlen += len(W) + + return mhashit(sha, 0, T[:]) +} + +/* calculate common key on client side */ +/* wCID = w.(A+AT) */ +func MPIN_CLIENT_KEY(sha int, G1 []byte, G2 []byte, pin int, R []byte, X []byte, H []byte, wCID []byte, CK []byte) int { + + g1 := FP12_fromBytes(G1) + g2 := FP12_fromBytes(G2) + z := FromBytes(R) + x := FromBytes(X) + h := FromBytes(H) + + W := ECP_fromBytes(wCID) + if W.Is_infinity() { + return INVALID_POINT + } + + W = G1mul(W, x) + + r := NewBIGints(CURVE_Order) + + z.add(h) //new + z.Mod(r) + + g2.pinpow(pin, int(PBLEN)) + g1.Mul(g2) + + c := g1.Compow(z, r) + + t := mpin_hash(sha, c, W) + + for i := 0; i < AESKEY; i++ { + CK[i] = t[i] + } + + return 0 +} + +/* calculate common key on server side */ +/* Z=r.A - no time permits involved */ + +func MPIN_SERVER_KEY(sha int, Z []byte, SST []byte, W []byte, H []byte, HID []byte, xID []byte, xCID []byte, SK []byte) int { + sQ := ECP2_fromBytes(SST) + if sQ.Is_infinity() { + return INVALID_POINT + } + R := ECP_fromBytes(Z) + if R.Is_infinity() { + return INVALID_POINT + } + A := ECP_fromBytes(HID) + if A.Is_infinity() { + return INVALID_POINT + } + + var U *ECP + if xCID != nil { + U = ECP_fromBytes(xCID) + } else { + U = ECP_fromBytes(xID) + } + if U.Is_infinity() { + return INVALID_POINT + } + + w := FromBytes(W) + h := FromBytes(H) + A = G1mul(A, h) // new + R.Add(A) + + U = G1mul(U, w) + g := Ate(sQ, R) + g = Fexp(g) + + c := g.trace() + + t := mpin_hash(sha, c, U) + + for i := 0; i < AESKEY; i++ { + SK[i] = t[i] + } + + return 0 +} + +/* return time since epoch */ +func MPIN_GET_TIME() int { + now := time.Now() + return int(now.Unix()) +} + +/* Generate Y = H(epoch, xCID/xID) */ +func MPIN_GET_Y(sha int, TimeValue int, xCID []byte, Y []byte) { + h := mhashit(sha, int32(TimeValue), xCID) + y := FromBytes(h) + q := NewBIGints(CURVE_Order) + y.Mod(q) + y.ToBytes(Y) +} + +/* One pass MPIN Client */ +func MPIN_CLIENT(sha int, date int, CLIENT_ID []byte, RNG *amcl.RAND, X []byte, pin int, TOKEN []byte, SEC []byte, xID []byte, xCID []byte, PERMIT []byte, TimeValue int, Y []byte) int { + rtn := 0 + + var pID []byte + if date == 0 { + pID = xID + } else { + pID = xCID + } + + rtn = MPIN_CLIENT_1(sha, date, CLIENT_ID, RNG, X, pin, TOKEN, SEC, xID, xCID, PERMIT) + if rtn != 0 { + return rtn + } + + MPIN_GET_Y(sha, TimeValue, pID, Y) + + rtn = MPIN_CLIENT_2(X, Y, SEC) + if rtn != 0 { + return rtn + } + + return 0 +} + +/* One pass MPIN Server */ +func MPIN_SERVER(sha int, date int, HID []byte, HTID []byte, Y []byte, SST []byte, xID []byte, xCID []byte, SEC []byte, E []byte, F []byte, CID []byte, TimeValue int) int { + rtn := 0 + + var pID []byte + if date == 0 { + pID = xID + } else { + pID = xCID + } + + MPIN_SERVER_1(sha, date, CID, HID, HTID) + MPIN_GET_Y(sha, TimeValue, pID, Y) + + rtn = MPIN_SERVER_2(date, HID, HTID, Y, SST, xID, xCID, SEC, E, F) + if rtn != 0 { + return rtn + } + + return 0 +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR.go index 77599599e5e..be13a7d4d28 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -21,8 +23,6 @@ under the License. package FP256BN - - /* Line function */ func line(A *ECP2, B *ECP2, Qx *FP, Qy *FP) *FP12 { var a *FP4 @@ -123,17 +123,17 @@ func line(A *ECP2, B *ECP2, Qx *FP, Qy *FP) *FP12 { A.Add(B) } - r:=NewFP12fp4s(a, b, c) - r.stype=FP_SPARSER + r := NewFP12fp4s(a, b, c) + r.stype = FP_SPARSER return r } /* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */ -func lbits(n3 *BIG,n *BIG) int { +func lbits(n3 *BIG, n *BIG) int { n.copy(NewBIGints(CURVE_Bnx)) - if CURVE_PAIRING_TYPE==BN { + if CURVE_PAIRING_TYPE == BN { n.pmul(6) - if SIGN_OF_X==POSITIVEX { + if SIGN_OF_X == POSITIVEX { n.inc(2) } else { n.dec(2) @@ -150,21 +150,21 @@ func lbits(n3 *BIG,n *BIG) int { /* prepare for multi-pairing */ func initmp() []*FP12 { var r []*FP12 - for i:=ATE_BITS-1; i>=0; i-- { - r=append(r,NewFP12int(1)) + for i := ATE_BITS - 1; i >= 0; i-- { + r = append(r, NewFP12int(1)) } return r } /* basic Miller loop */ func miller(r []*FP12) *FP12 { - res:=NewFP12int(1); - for i:=ATE_BITS-1; i>=1; i-- { + res := NewFP12int(1) + for i := ATE_BITS - 1; i >= 1; i-- { res.sqr() - res.ssmul(r[i]); + res.ssmul(r[i]) } - if SIGN_OF_X==NEGATIVEX { + if SIGN_OF_X == NEGATIVEX { res.conj() } res.ssmul(r[0]) @@ -172,27 +172,27 @@ func miller(r []*FP12) *FP12 { } /* Accumulate another set of line functions for n-pairing */ -func another(r []*FP12,P1 *ECP2,Q1 *ECP) { - f:=NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) - n:=NewBIG() - n3:=NewBIG() - K:=NewECP2(); - var lv,lv2 *FP12 +func another(r []*FP12, P1 *ECP2, Q1 *ECP) { + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + n := NewBIG() + n3 := NewBIG() + K := NewECP2() + var lv, lv2 *FP12 if Q1.Is_infinity() { return } -// P is needed in affine form for line function, Q for (Qx,Qy) extraction - P:=NewECP2() + // P is needed in affine form for line function, Q for (Qx,Qy) extraction + P := NewECP2() P.Copy(P1) - Q:=NewECP() + Q := NewECP() Q.Copy(Q1) P.Affine() Q.Affine() - if CURVE_PAIRING_TYPE==BN { - if SEXTIC_TWIST==M_TYPE { + if CURVE_PAIRING_TYPE == BN { + if SEXTIC_TWIST == M_TYPE { f.inverse() f.norm() } @@ -201,52 +201,53 @@ func another(r []*FP12,P1 *ECP2,Q1 *ECP) { Qx := NewFPcopy(Q.getx()) Qy := NewFPcopy(Q.gety()) - A:=NewECP2() + A := NewECP2() A.Copy(P) - MP:=NewECP2() - MP.Copy(P); MP.neg() + MP := NewECP2() + MP.Copy(P) + MP.neg() - nb:=lbits(n3,n) + nb := lbits(n3, n) - for i:=nb-2;i>=1;i-- { - lv=line(A,A,Qx,Qy) + for i := nb - 2; i >= 1; i-- { + lv = line(A, A, Qx, Qy) - bt:=n3.bit(i)-n.bit(i) - if bt==1 { - lv2=line(A,P,Qx,Qy) + bt := n3.bit(i) - n.bit(i) + if bt == 1 { + lv2 = line(A, P, Qx, Qy) lv.smul(lv2) } - if bt==-1 { - lv2=line(A,MP,Qx,Qy) + if bt == -1 { + lv2 = line(A, MP, Qx, Qy) lv.smul(lv2) } r[i].ssmul(lv) } -/* R-ate fixup required for BN curves */ - if CURVE_PAIRING_TYPE==BN { - if SIGN_OF_X==NEGATIVEX { + /* R-ate fixup required for BN curves */ + if CURVE_PAIRING_TYPE == BN { + if SIGN_OF_X == NEGATIVEX { A.neg() } K.Copy(P) K.frob(f) - lv=line(A,K,Qx,Qy) + lv = line(A, K, Qx, Qy) K.frob(f) K.neg() - lv2=line(A,K,Qx,Qy) + lv2 = line(A, K, Qx, Qy) lv.smul(lv2) r[0].ssmul(lv) - } + } } /* Optimal R-ate pairing */ func Ate(P1 *ECP2, Q1 *ECP) *FP12 { f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) - n:=NewBIG() - n3:=NewBIG() + n := NewBIG() + n3 := NewBIG() K := NewECP2() - var lv,lv2 *FP12 + var lv, lv2 *FP12 if Q1.Is_infinity() { return NewFP12int(1) @@ -278,7 +279,7 @@ func Ate(P1 *ECP2, Q1 *ECP) *FP12 { NP.Copy(P) NP.neg() - nb:=lbits(n3,n) + nb := lbits(n3, n) for i := nb - 2; i >= 1; i-- { r.sqr() @@ -322,16 +323,16 @@ func Ate(P1 *ECP2, Q1 *ECP) *FP12 { /* Optimal R-ate double pairing e(P,Q).e(R,S) */ func Ate2(P1 *ECP2, Q1 *ECP, R1 *ECP2, S1 *ECP) *FP12 { f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) - n:=NewBIG() - n3:=NewBIG() + n := NewBIG() + n3 := NewBIG() K := NewECP2() - var lv,lv2 *FP12 + var lv, lv2 *FP12 if Q1.Is_infinity() { - return Ate(R1,S1) + return Ate(R1, S1) } if S1.Is_infinity() { - return Ate(P1,Q1) + return Ate(P1, Q1) } if CURVE_PAIRING_TYPE == BN { @@ -372,7 +373,7 @@ func Ate2(P1 *ECP2, Q1 *ECP, R1 *ECP2, S1 *ECP) *FP12 { NR.Copy(R) NR.neg() - nb:=lbits(n3,n) + nb := lbits(n3, n) for i := nb - 2; i >= 1; i-- { r.sqr() @@ -443,10 +444,10 @@ func Fexp(m *FP12) *FP12 { r.frob(f) r.frob(f) r.Mul(lv) -// if r.Isunity() { -// r.zero() -// return r -// } + // if r.Isunity() { + // r.zero() + // return r + // } /* Hard part of final exp */ if CURVE_PAIRING_TYPE == BN { lv.Copy(r) diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR_32.go new file mode 100644 index 00000000000..541105be198 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/PAIR_32.go @@ -0,0 +1,766 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* MiotCL BN Curve Pairing functions */ + +package FP256BN + +/* Line function */ +func line(A *ECP2, B *ECP2, Qx *FP, Qy *FP) *FP12 { + var a *FP4 + var b *FP4 + var c *FP4 + + if A == B { /* Doubling */ + XX := NewFP2copy(A.getx()) //X + YY := NewFP2copy(A.gety()) //Y + ZZ := NewFP2copy(A.getz()) //Z + YZ := NewFP2copy(YY) //Y + YZ.mul(ZZ) //YZ + XX.sqr() //X^2 + YY.sqr() //Y^2 + ZZ.sqr() //Z^2 + + YZ.imul(4) + YZ.neg() + YZ.norm() //-4YZ + YZ.pmul(Qy) //-4YZ.Ys + + XX.imul(6) //6X^2 + XX.pmul(Qx) //6X^2.Xs + + sb := 3 * CURVE_B_I + ZZ.imul(sb) // 3bZ^2 + if SEXTIC_TWIST == D_TYPE { + ZZ.div_ip2() + } + if SEXTIC_TWIST == M_TYPE { + ZZ.mul_ip() + ZZ.add(ZZ) + YZ.mul_ip() + YZ.norm() + } + ZZ.norm() // 3b.Z^2 + + YY.add(YY) + ZZ.sub(YY) + ZZ.norm() // 3b.Z^2-2Y^2 + + a = NewFP4fp2s(YZ, ZZ) // -4YZ.Ys | 3b.Z^2-2Y^2 | 6X^2.Xs + if SEXTIC_TWIST == D_TYPE { + + b = NewFP4fp2(XX) // L(0,1) | L(0,0) | L(1,0) + c = NewFP4() + } + if SEXTIC_TWIST == M_TYPE { + b = NewFP4() + c = NewFP4fp2(XX) + c.times_i() + } + A.dbl() + + } else { /* Addition */ + + X1 := NewFP2copy(A.getx()) // X1 + Y1 := NewFP2copy(A.gety()) // Y1 + T1 := NewFP2copy(A.getz()) // Z1 + T2 := NewFP2copy(A.getz()) // Z1 + + T1.mul(B.gety()) // T1=Z1.Y2 + T2.mul(B.getx()) // T2=Z1.X2 + + X1.sub(T2) + X1.norm() // X1=X1-Z1.X2 + Y1.sub(T1) + Y1.norm() // Y1=Y1-Z1.Y2 + + T1.copy(X1) // T1=X1-Z1.X2 + X1.pmul(Qy) // X1=(X1-Z1.X2).Ys + + if SEXTIC_TWIST == M_TYPE { + X1.mul_ip() + X1.norm() + } + + T1.mul(B.gety()) // T1=(X1-Z1.X2).Y2 + + T2.copy(Y1) // T2=Y1-Z1.Y2 + T2.mul(B.getx()) // T2=(Y1-Z1.Y2).X2 + T2.sub(T1) + T2.norm() // T2=(Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 + Y1.pmul(Qx) + Y1.neg() + Y1.norm() // Y1=-(Y1-Z1.Y2).Xs + + a = NewFP4fp2s(X1, T2) // (X1-Z1.X2).Ys | (Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 | - (Y1-Z1.Y2).Xs + if SEXTIC_TWIST == D_TYPE { + b = NewFP4fp2(Y1) + c = NewFP4() + } + if SEXTIC_TWIST == M_TYPE { + b = NewFP4() + c = NewFP4fp2(Y1) + c.times_i() + } + A.Add(B) + } + + r := NewFP12fp4s(a, b, c) + r.stype = FP_SPARSER + return r +} + +/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */ +func lbits(n3 *BIG, n *BIG) int { + n.copy(NewBIGints(CURVE_Bnx)) + if CURVE_PAIRING_TYPE == BN { + n.pmul(6) + if SIGN_OF_X == POSITIVEX { + n.inc(2) + } else { + n.dec(2) + } + } + + n.norm() + n3.copy(n) + n3.pmul(3) + n3.norm() + return n3.nbits() +} + +/* prepare for multi-pairing */ +func initmp() []*FP12 { + var r []*FP12 + for i := ATE_BITS - 1; i >= 0; i-- { + r = append(r, NewFP12int(1)) + } + return r +} + +/* basic Miller loop */ +func miller(r []*FP12) *FP12 { + res := NewFP12int(1) + for i := ATE_BITS - 1; i >= 1; i-- { + res.sqr() + res.ssmul(r[i]) + } + + if SIGN_OF_X == NEGATIVEX { + res.conj() + } + res.ssmul(r[0]) + return res +} + +/* Accumulate another set of line functions for n-pairing */ +func another(r []*FP12, P1 *ECP2, Q1 *ECP) { + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + n := NewBIG() + n3 := NewBIG() + K := NewECP2() + var lv, lv2 *FP12 + + if Q1.Is_infinity() { + return + } + // P is needed in affine form for line function, Q for (Qx,Qy) extraction + P := NewECP2() + P.Copy(P1) + Q := NewECP() + Q.Copy(Q1) + + P.Affine() + Q.Affine() + + if CURVE_PAIRING_TYPE == BN { + if SEXTIC_TWIST == M_TYPE { + f.inverse() + f.norm() + } + } + + Qx := NewFPcopy(Q.getx()) + Qy := NewFPcopy(Q.gety()) + + A := NewECP2() + A.Copy(P) + + MP := NewECP2() + MP.Copy(P) + MP.neg() + + nb := lbits(n3, n) + + for i := nb - 2; i >= 1; i-- { + lv = line(A, A, Qx, Qy) + + bt := n3.bit(i) - n.bit(i) + if bt == 1 { + lv2 = line(A, P, Qx, Qy) + lv.smul(lv2) + } + if bt == -1 { + lv2 = line(A, MP, Qx, Qy) + lv.smul(lv2) + } + r[i].ssmul(lv) + } + + /* R-ate fixup required for BN curves */ + if CURVE_PAIRING_TYPE == BN { + if SIGN_OF_X == NEGATIVEX { + A.neg() + } + K.Copy(P) + K.frob(f) + lv = line(A, K, Qx, Qy) + K.frob(f) + K.neg() + lv2 = line(A, K, Qx, Qy) + lv.smul(lv2) + r[0].ssmul(lv) + } +} + +/* Optimal R-ate pairing */ +func Ate(P1 *ECP2, Q1 *ECP) *FP12 { + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + n := NewBIG() + n3 := NewBIG() + K := NewECP2() + var lv, lv2 *FP12 + + if Q1.Is_infinity() { + return NewFP12int(1) + } + + if CURVE_PAIRING_TYPE == BN { + if SEXTIC_TWIST == M_TYPE { + f.inverse() + f.norm() + } + } + + P := NewECP2() + P.Copy(P1) + P.Affine() + Q := NewECP() + Q.Copy(Q1) + Q.Affine() + + Qx := NewFPcopy(Q.getx()) + Qy := NewFPcopy(Q.gety()) + + A := NewECP2() + r := NewFP12int(1) + + A.Copy(P) + + NP := NewECP2() + NP.Copy(P) + NP.neg() + + nb := lbits(n3, n) + + for i := nb - 2; i >= 1; i-- { + r.sqr() + lv = line(A, A, Qx, Qy) + bt := n3.bit(i) - n.bit(i) + if bt == 1 { + lv2 = line(A, P, Qx, Qy) + lv.smul(lv2) + } + if bt == -1 { + lv2 = line(A, NP, Qx, Qy) + lv.smul(lv2) + } + r.ssmul(lv) + } + + if SIGN_OF_X == NEGATIVEX { + r.conj() + } + + /* R-ate fixup required for BN curves */ + + if CURVE_PAIRING_TYPE == BN { + if SIGN_OF_X == NEGATIVEX { + A.neg() + } + + K.Copy(P) + K.frob(f) + lv = line(A, K, Qx, Qy) + K.frob(f) + K.neg() + lv2 = line(A, K, Qx, Qy) + lv.smul(lv2) + r.ssmul(lv) + } + + return r +} + +/* Optimal R-ate double pairing e(P,Q).e(R,S) */ +func Ate2(P1 *ECP2, Q1 *ECP, R1 *ECP2, S1 *ECP) *FP12 { + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + n := NewBIG() + n3 := NewBIG() + K := NewECP2() + var lv, lv2 *FP12 + + if Q1.Is_infinity() { + return Ate(R1, S1) + } + if S1.Is_infinity() { + return Ate(P1, Q1) + } + + if CURVE_PAIRING_TYPE == BN { + if SEXTIC_TWIST == M_TYPE { + f.inverse() + f.norm() + } + } + + P := NewECP2() + P.Copy(P1) + P.Affine() + Q := NewECP() + Q.Copy(Q1) + Q.Affine() + R := NewECP2() + R.Copy(R1) + R.Affine() + S := NewECP() + S.Copy(S1) + S.Affine() + + Qx := NewFPcopy(Q.getx()) + Qy := NewFPcopy(Q.gety()) + Sx := NewFPcopy(S.getx()) + Sy := NewFPcopy(S.gety()) + + A := NewECP2() + B := NewECP2() + r := NewFP12int(1) + + A.Copy(P) + B.Copy(R) + NP := NewECP2() + NP.Copy(P) + NP.neg() + NR := NewECP2() + NR.Copy(R) + NR.neg() + + nb := lbits(n3, n) + + for i := nb - 2; i >= 1; i-- { + r.sqr() + lv = line(A, A, Qx, Qy) + lv2 = line(B, B, Sx, Sy) + lv.smul(lv2) + r.ssmul(lv) + bt := n3.bit(i) - n.bit(i) + if bt == 1 { + lv = line(A, P, Qx, Qy) + lv2 = line(B, R, Sx, Sy) + lv.smul(lv2) + r.ssmul(lv) + } + if bt == -1 { + lv = line(A, NP, Qx, Qy) + lv2 = line(B, NR, Sx, Sy) + lv.smul(lv2) + r.ssmul(lv) + } + } + + if SIGN_OF_X == NEGATIVEX { + r.conj() + } + + /* R-ate fixup */ + if CURVE_PAIRING_TYPE == BN { + if SIGN_OF_X == NEGATIVEX { + A.neg() + B.neg() + } + K.Copy(P) + K.frob(f) + + lv = line(A, K, Qx, Qy) + K.frob(f) + K.neg() + lv2 = line(A, K, Qx, Qy) + lv.smul(lv2) + r.ssmul(lv) + K.Copy(R) + K.frob(f) + lv = line(B, K, Sx, Sy) + K.frob(f) + K.neg() + lv2 = line(B, K, Sx, Sy) + lv.smul(lv2) + r.ssmul(lv) + } + + return r +} + +/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */ +func Fexp(m *FP12) *FP12 { + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + x := NewBIGints(CURVE_Bnx) + r := NewFP12copy(m) + + /* Easy part of final exp */ + lv := NewFP12copy(r) + lv.Inverse() + r.conj() + + r.Mul(lv) + lv.Copy(r) + r.frob(f) + r.frob(f) + r.Mul(lv) + // if r.Isunity() { + // r.zero() + // return r + // } + /* Hard part of final exp */ + if CURVE_PAIRING_TYPE == BN { + lv.Copy(r) + lv.frob(f) + x0 := NewFP12copy(lv) + x0.frob(f) + lv.Mul(r) + x0.Mul(lv) + x0.frob(f) + x1 := NewFP12copy(r) + x1.conj() + x4 := r.Pow(x) + if SIGN_OF_X == POSITIVEX { + x4.conj() + } + + x3 := NewFP12copy(x4) + x3.frob(f) + + x2 := x4.Pow(x) + if SIGN_OF_X == POSITIVEX { + x2.conj() + } + + x5 := NewFP12copy(x2) + x5.conj() + lv = x2.Pow(x) + if SIGN_OF_X == POSITIVEX { + lv.conj() + } + + x2.frob(f) + r.Copy(x2) + r.conj() + + x4.Mul(r) + x2.frob(f) + + r.Copy(lv) + r.frob(f) + lv.Mul(r) + + lv.usqr() + lv.Mul(x4) + lv.Mul(x5) + r.Copy(x3) + r.Mul(x5) + r.Mul(lv) + lv.Mul(x2) + r.usqr() + r.Mul(lv) + r.usqr() + lv.Copy(r) + lv.Mul(x1) + r.Mul(x0) + lv.usqr() + r.Mul(lv) + r.reduce() + } else { + + // Ghamman & Fouotsa Method + y0 := NewFP12copy(r) + y0.usqr() + y1 := y0.Pow(x) + if SIGN_OF_X == NEGATIVEX { + y1.conj() + } + + x.fshr(1) + y2 := y1.Pow(x) + if SIGN_OF_X == NEGATIVEX { + y2.conj() + } + + x.fshl(1) + y3 := NewFP12copy(r) + y3.conj() + y1.Mul(y3) + + y1.conj() + y1.Mul(y2) + + y2 = y1.Pow(x) + if SIGN_OF_X == NEGATIVEX { + y2.conj() + } + + y3 = y2.Pow(x) + if SIGN_OF_X == NEGATIVEX { + y3.conj() + } + + y1.conj() + y3.Mul(y1) + + y1.conj() + y1.frob(f) + y1.frob(f) + y1.frob(f) + y2.frob(f) + y2.frob(f) + y1.Mul(y2) + + y2 = y3.Pow(x) + if SIGN_OF_X == NEGATIVEX { + y2.conj() + } + + y2.Mul(y0) + y2.Mul(r) + + y1.Mul(y2) + y2.Copy(y3) + y2.frob(f) + y1.Mul(y2) + r.Copy(y1) + r.reduce() + } + return r +} + +/* GLV method */ +func glv(e *BIG) []*BIG { + var u []*BIG + if CURVE_PAIRING_TYPE == BN { + t := NewBIGint(0) + q := NewBIGints(CURVE_Order) + var v []*BIG + + for i := 0; i < 2; i++ { + t.copy(NewBIGints(CURVE_W[i])) // why not just t=new BIG(ROM.CURVE_W[i]); + d := mul(t, e) + v = append(v, NewBIGcopy(d.div(q))) + u = append(u, NewBIGint(0)) + } + u[0].copy(e) + for i := 0; i < 2; i++ { + for j := 0; j < 2; j++ { + t.copy(NewBIGints(CURVE_SB[j][i])) + t.copy(Modmul(v[j], t, q)) + u[i].add(q) + u[i].sub(t) + u[i].Mod(q) + } + } + } else { + q := NewBIGints(CURVE_Order) + x := NewBIGints(CURVE_Bnx) + x2 := smul(x, x) + u = append(u, NewBIGcopy(e)) + u[0].Mod(x2) + u = append(u, NewBIGcopy(e)) + u[1].div(x2) + u[1].rsub(q) + } + return u +} + +/* Galbraith & Scott Method */ +func gs(e *BIG) []*BIG { + var u []*BIG + if CURVE_PAIRING_TYPE == BN { + t := NewBIGint(0) + q := NewBIGints(CURVE_Order) + + var v []*BIG + for i := 0; i < 4; i++ { + t.copy(NewBIGints(CURVE_WB[i])) + d := mul(t, e) + v = append(v, NewBIGcopy(d.div(q))) + u = append(u, NewBIGint(0)) + } + u[0].copy(e) + for i := 0; i < 4; i++ { + for j := 0; j < 4; j++ { + t.copy(NewBIGints(CURVE_BB[j][i])) + t.copy(Modmul(v[j], t, q)) + u[i].add(q) + u[i].sub(t) + u[i].Mod(q) + } + } + } else { + q := NewBIGints(CURVE_Order) + x := NewBIGints(CURVE_Bnx) + w := NewBIGcopy(e) + for i := 0; i < 3; i++ { + u = append(u, NewBIGcopy(w)) + u[i].Mod(x) + w.div(x) + } + u = append(u, NewBIGcopy(w)) + if SIGN_OF_X == NEGATIVEX { + u[1].copy(Modneg(u[1], q)) + u[3].copy(Modneg(u[3], q)) + } + } + return u +} + +/* Multiply P by e in group G1 */ +func G1mul(P *ECP, e *BIG) *ECP { + var R *ECP + if USE_GLV { + R = NewECP() + R.Copy(P) + Q := NewECP() + Q.Copy(P) + Q.Affine() + q := NewBIGints(CURVE_Order) + cru := NewFPbig(NewBIGints(CURVE_Cru)) + t := NewBIGint(0) + u := glv(e) + Q.getx().mul(cru) + + np := u[0].nbits() + t.copy(Modneg(u[0], q)) + nn := t.nbits() + if nn < np { + u[0].copy(t) + R.neg() + } + + np = u[1].nbits() + t.copy(Modneg(u[1], q)) + nn = t.nbits() + if nn < np { + u[1].copy(t) + Q.neg() + } + u[0].norm() + u[1].norm() + R = R.Mul2(u[0], Q, u[1]) + + } else { + R = P.mul(e) + } + return R +} + +/* Multiply P by e in group G2 */ +func G2mul(P *ECP2, e *BIG) *ECP2 { + var R *ECP2 + if USE_GS_G2 { + var Q []*ECP2 + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + + if SEXTIC_TWIST == M_TYPE { + f.inverse() + f.norm() + } + + q := NewBIGints(CURVE_Order) + u := gs(e) + + t := NewBIGint(0) + Q = append(Q, NewECP2()) + Q[0].Copy(P) + for i := 1; i < 4; i++ { + Q = append(Q, NewECP2()) + Q[i].Copy(Q[i-1]) + Q[i].frob(f) + } + for i := 0; i < 4; i++ { + np := u[i].nbits() + t.copy(Modneg(u[i], q)) + nn := t.nbits() + if nn < np { + u[i].copy(t) + Q[i].neg() + } + u[i].norm() + } + + R = mul4(Q, u) + + } else { + R = P.mul(e) + } + return R +} + +/* f=f^e */ +/* Note that this method requires a lot of RAM! Better to use compressed XTR method, see FP4.java */ +func GTpow(d *FP12, e *BIG) *FP12 { + var r *FP12 + if USE_GS_GT { + var g []*FP12 + f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb)) + q := NewBIGints(CURVE_Order) + t := NewBIGint(0) + + u := gs(e) + + g = append(g, NewFP12copy(d)) + for i := 1; i < 4; i++ { + g = append(g, NewFP12()) + g[i].Copy(g[i-1]) + g[i].frob(f) + } + for i := 0; i < 4; i++ { + np := u[i].nbits() + t.copy(Modneg(u[i], q)) + nn := t.nbits() + if nn < np { + u[i].copy(t) + g[i].conj() + } + u[i].norm() + } + r = pow4(g, u) + } else { + r = d.Pow(e) + } + return r +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM.go index 4bd8a77ddf1..0620d07e8cc 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM.go +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -49,4 +51,3 @@ var CURVE_W = [2][5]Chunk{{0xF0036E1B054003, 0xFFFFFFFE78663A, 0xFFFF, 0x0, 0x0} var CURVE_SB = [2][2][5]Chunk{{{0xF5EEEE7C669004, 0xFFFFFFFE78670B, 0xFFFF, 0x0, 0x0}, {0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0}}, {{0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0}, {0x3D4FFEB606100A, 0x65FB129B19B4BB, 0x5EEE71A49D0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}}} var CURVE_WB = [4][5]Chunk{{0x20678F0D30A800, 0x55555554D2CC10, 0x5555, 0x0, 0x0}, {0xD6764C0D7DC805, 0x8FBEA10BC3AD1A, 0x806160104467DE, 0xD105EB, 0x0}, {0xACB6061F173803, 0x47DF5085E1D6C1, 0xC030B0082233EF, 0x6882F5, 0x0}, {0x26530F6E91F801, 0x55555554D2CCE1, 0x5555, 0x0, 0x0}} var CURVE_BB = [4][4][5]Chunk{{{0xAA5DACA05AA80D, 0x65FB1299921A8D, 0x5EEE71A49E0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}, {0xAA5DACA05AA80C, 0x65FB1299921A8D, 0x5EEE71A49E0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}, {0xAA5DACA05AA80C, 0x65FB1299921A8D, 0x5EEE71A49E0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}, {0x5EB8061615002, 0xD1, 0x0, 0x0, 0x0}}, {{0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0}, {0xAA5DACA05AA80C, 0x65FB1299921A8D, 0x5EEE71A49E0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}, {0xAA5DACA05AA80D, 0x65FB1299921A8D, 0x5EEE71A49E0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}, {0xAA5DACA05AA80C, 0x65FB1299921A8D, 0x5EEE71A49E0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}}, {{0x5EB8061615002, 0xD1, 0x0, 0x0, 0x0}, {0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0}, {0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0}, {0x5EB8061615001, 0xD1, 0x0, 0x0, 0x0}}, {{0x82F5C030B0A802, 0x68, 0x0, 0x0, 0x0}, {0xBD700C2C2A002, 0x1A2, 0x0, 0x0, 0x0}, {0x2767EC6FAA000A, 0x65FB1299921A25, 0x5EEE71A49E0CDC, 0xFFFCF0CD46E5F2, 0xFFFFFFFF}, {0x82F5C030B0A802, 0x68, 0x0, 0x0, 0x0}}} - diff --git a/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM_32.go b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM_32.go new file mode 100644 index 00000000000..cfc3018a967 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/amcl/FP256BN/ROM_32.go @@ -0,0 +1,53 @@ +//go:build 386 || arm + +/* +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +*/ + +/* Fixed Data in ROM - Field and Curve parameters */ + +package FP256BN + +// Base Bits= 28 +var Modulus = [...]Chunk{0xED33013, 0x292DDBA, 0x80A82D3, 0x65FB129, 0x49F0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF} +var R2modp = [...]Chunk{0x3B9F8B, 0xEDE3363, 0xFEC54E8, 0x92FFEE9, 0x3C55F79, 0x13C1C06, 0xC0123FA, 0xA12F2EA, 0xE559B2A, 0x8} + +const MConst Chunk = 0x537E5E5 + +const CURVE_Cof_I int = 1 +const CURVE_A int = 0 +const CURVE_B_I int = 3 + +var CURVE_B = [...]Chunk{0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} +var CURVE_Order = [...]Chunk{0x10B500D, 0x2D536CD, 0x9921AF6, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF} +var CURVE_Gx = [...]Chunk{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} +var CURVE_Gy = [...]Chunk{0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} + +var Fra = [...]Chunk{0xF943106, 0x760328A, 0xAB28F74, 0x71511E3, 0x7CF39A1, 0x8DDB086, 0x52D1A6E, 0xCA786F3, 0xD617662, 0x3} +var Frb = [...]Chunk{0xF3EFF0D, 0xB32AB2F, 0xD57F35E, 0xF4A9F45, 0xCCFD33A, 0xD113693, 0x819CB83, 0x3584819, 0x29E899D, 0xC} +var CURVE_Bnx = [...]Chunk{0xB0A801, 0x82F5C03, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} +var CURVE_Cof = [...]Chunk{0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} +var CURVE_Cru = [...]Chunk{0x3A1B807, 0x1C0A24A, 0x32D1EDB, 0xD79DF19, 0x8659BCD, 0x4092101, 0x13988E1, 0x0, 0x0, 0x0} +var CURVE_Pxa = [...]Chunk{0x9C09EFB, 0x2616B68, 0xF843CD2, 0x539A12B, 0x13ACE1C, 0x577C289, 0x28560F, 0xB4C96C2, 0xE0C3350, 0xF} +var CURVE_Pxb = [...]Chunk{0x37E6A2B, 0x69ED34A, 0x3589D2, 0x78E287D, 0x3B924DD, 0xC637D81, 0x4DB5AE1, 0x738AC05, 0xEA66057, 0x4} +var CURVE_Pya = [...]Chunk{0xEDC27FF, 0x9B481B, 0x15848E9, 0x24758D6, 0xE51EFCB, 0x75124E3, 0x376770D, 0xC542A3B, 0x2046E7, 0x7} +var CURVE_Pyb = [...]Chunk{0xAAD049B, 0x1281114, 0xA98B3E0, 0xBE80821, 0x29F8B4C, 0x49297EB, 0x42EEA6, 0xD388C29, 0x554E3BC, 0x0} +var CURVE_W = [2][10]Chunk{{0xB054003, 0xF0036E1, 0xE78663A, 0xFFFFFFF, 0xFFFF, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}} +var CURVE_SB = [2][2][10]Chunk{{{0xC669004, 0xF5EEEE7, 0xE78670B, 0xFFFFFFF, 0xFFFF, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, {{0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x606100A, 0x3D4FFEB, 0xB19B4BB, 0x65FB129, 0x49D0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}}} +var CURVE_WB = [4][10]Chunk{{0xD30A800, 0x20678F0, 0x4D2CC10, 0x5555555, 0x5555, 0x0, 0x0, 0x0, 0x0, 0x0}, {0xD7DC805, 0xD6764C0, 0xBC3AD1A, 0x8FBEA10, 0x4467DE, 0x8061601, 0xD105EB, 0x0, 0x0, 0x0}, {0xF173803, 0xACB6061, 0x5E1D6C1, 0x47DF508, 0x82233EF, 0xC030B00, 0x6882F5, 0x0, 0x0, 0x0}, {0xE91F801, 0x26530F6, 0x4D2CCE1, 0x5555555, 0x5555, 0x0, 0x0, 0x0, 0x0, 0x0}} +var CURVE_BB = [4][4][10]Chunk{{{0x5AA80D, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}, {0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}, {0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}, {0x1615002, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, {{0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}, {0x5AA80D, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}, {0x5AA80C, 0xAA5DACA, 0x9921A8D, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}}, {{0x1615002, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x1615001, 0x5EB806, 0xD1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}, {{0xB0A802, 0x82F5C03, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0x2C2A002, 0xBD700C, 0x1A2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, {0xFAA000A, 0x2767EC6, 0x9921A25, 0x65FB129, 0x49E0CDC, 0x5EEE71A, 0xD46E5F2, 0xFFFCF0C, 0xFFFFFFF, 0xF}, {0xB0A802, 0x82F5C03, 0x68, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}} diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/AES.go b/vendor/github.com/hyperledger/fabric-amcl/core/AES.go index 5767e6666ff..4021de5b873 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/AES.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/AES.go @@ -21,7 +21,7 @@ package core -//import "fmt" + const AES_ECB int = 0 const AES_CBC int = 1 diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/DILITHIUM.go b/vendor/github.com/hyperledger/fabric-amcl/core/DILITHIUM.go new file mode 100644 index 00000000000..7755665a73a --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/core/DILITHIUM.go @@ -0,0 +1,1290 @@ +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + + Arwa Alblooshi 15/12/2022 + */ +package core + + + +//q = 8380417 +const DL_LGN = 8 +const DL_DEGREE = (1 << DL_LGN) +const DL_PRIME = 0x7fe001 +const DL_D = 13 +const DL_TD = (23 - DL_D) + +const DL_ONE = 0x3FFE00 // R mod Q +const DL_COMBO = 0xA3FA // ONE*inv mod Q +const DL_R2MODP = 0x2419FF // R^2 mod Q +const DL_ND = 0xFC7FDFFF // 1/(R-Q) mod R + +const DL_MAXLG = 19 +const DL_MAXK = 8 // could reduce these if not using highest security +const DL_MAXL = 7 +const DL_YBYTES = (((DL_MAXLG + 1) * DL_DEGREE) / 8) + +const DL_SK_SIZE_2 = (32*3+DL_DEGREE* (4*13+4*3+4*3)/8) +const DL_PK_SIZE_2 = ((4*DL_DEGREE*DL_TD)/8 + 32) +const DL_SIG_SIZE_2 = ((DL_DEGREE*4*(17+1))/8 + 80 + 4 + 32) + +const DL_SK_SIZE_3 = (32*3 + DL_DEGREE*(6*13+5*4+6*4)/8) +const DL_PK_SIZE_3 = ((6*DL_DEGREE*DL_TD)/8 + 32) +const DL_SIG_SIZE_3 = ((DL_DEGREE*5*(19+1))/8 + 55 + 6 + 32) + +const DL_SK_SIZE_5 = (32*3 + DL_DEGREE*(8*13+7*3+8*3)/8) +const DL_PK_SIZE_5 = ((8*DL_DEGREE*DL_TD)/8 + 32) +const DL_SIG_SIZE_5 = ((DL_DEGREE*7*(19+1))/8 + 75 + 8 + 32) + +// parameters for each security level +// tau,gamma1,gamma2,K,L,eta,lg(2*eta+1),omega + +var DL_PARAMS_2 = []int{39, 17, 88, 4, 4, 2, 3, 80} +var DL_PARAMS_3 = []int{49, 19, 32, 6, 5, 4, 4, 55} +var DL_PARAMS_5 = []int{60, 19, 32, 8, 7, 2, 3, 75} + +var DL_roots = []int32{0x3ffe00, 0x64f7, 0x581103, 0x77f504, 0x39e44, 0x740119, 0x728129, 0x71e24, 0x1bde2b, 0x23e92b, 0x7a64ae, 0x5ff480, 0x2f9a75, 0x53db0a, 0x2f7a49, 0x28e527, 0x299658, 0xfa070, 0x6f65a5, 0x36b788, 0x777d91, 0x6ecaa1, 0x27f968, 0x5fb37c, 0x5f8dd7, 0x44fae8, 0x6a84f8, 0x4ddc99, 0x1ad035, 0x7f9423, 0x3d3201, 0x445c5, 0x294a67, 0x17620, 0x2ef4cd, 0x35dec5, 0x668504, 0x49102d, 0x5927d5, 0x3bbeaf, 0x44f586, 0x516e7d, 0x368a96, 0x541e42, 0x360400, 0x7b4a4e, 0x23d69c, 0x77a55e, 0x65f23e, 0x66cad7, 0x357e1e, 0x458f5a, 0x35843f, 0x5f3618, 0x67745d, 0x38738c, 0xc63a8, 0x81b9a, 0xe8f76, 0x3b3853, 0x3b8534, 0x58dc31, 0x1f9d54, 0x552f2e, 0x43e6e6, 0x688c82, 0x47c1d0, 0x51781a, 0x69b65e, 0x3509ee, 0x2135c7, 0x67afbc, 0x6caf76, 0x1d9772, 0x419073, 0x709cf7, 0x4f3281, 0x4fb2af, 0x4870e1, 0x1efca, 0x3410f2, 0x70de86, 0x20c638, 0x296e9f, 0x5297a4, 0x47844c, 0x799a6e, 0x5a140a, 0x75a283, 0x6d2114, 0x7f863c, 0x6be9f8, 0x7a0bde, 0x1495d4, 0x1c4563, 0x6a0c63, 0x4cdbea, 0x40af0, 0x7c417, 0x2f4588, 0xad00, 0x6f16bf, 0xdcd44, 0x3c675a, 0x470bcb, 0x7fbe7f, 0x193948, 0x4e49c1, 0x24756c, 0x7ca7e0, 0xb98a1, 0x6bc809, 0x2e46c, 0x49a809, 0x3036c2, 0x639ff7, 0x5b1c94, 0x7d2ae1, 0x141305, 0x147792, 0x139e25, 0x67b0e1, 0x737945, 0x69e803, 0x51cea3, 0x44a79d, 0x488058, 0x3a97d9, 0x1fea93, 0x33ff5a, 0x2358d4, 0x3a41f8, 0x4cdf73, 0x223dfb, 0x5a8ba0, 0x498423, 0x412f5, 0x252587, 0x6d04f1, 0x359b5d, 0x4a28a1, 0x4682fd, 0x6d9b57, 0x4f25df, 0xdbe5e, 0x1c5e1a, 0xde0e6, 0xc7f5a, 0x78f83, 0x67428b, 0x7f3705, 0x77e6fd, 0x75e022, 0x503af7, 0x1f0084, 0x30ef86, 0x49997e, 0x77dcd7, 0x742593, 0x4901c3, 0x53919, 0x4610c, 0x5aad42, 0x3eb01b, 0x3472e7, 0x4ce03c, 0x1a7cc7, 0x31924, 0x2b5ee5, 0x291199, 0x585a3b, 0x134d71, 0x3de11c, 0x130984, 0x25f051, 0x185a46, 0x466519, 0x1314be, 0x283891, 0x49bb91, 0x52308a, 0x1c853f, 0x1d0b4b, 0x6fd6a7, 0x6b88bf, 0x12e11b, 0x4d3e3f, 0x6a0d30, 0x78fde5, 0x1406c7, 0x327283, 0x61ed6f, 0x6c5954, 0x1d4099, 0x590579, 0x6ae5ae, 0x16e405, 0xbdbe7, 0x221de8, 0x33f8cf, 0x779935, 0x54aa0d, 0x665ff9, 0x63b158, 0x58711c, 0x470c13, 0x910d8, 0x463e20, 0x612659, 0x251d8b, 0x2573b7, 0x7d5c90, 0x1ddd98, 0x336898, 0x2d4bb, 0x6d73a8, 0x4f4cbf, 0x27c1c, 0x18aa08, 0x2dfd71, 0xc5ca5, 0x19379a, 0x478168, 0x646c3e, 0x51813d, 0x35c539, 0x3b0115, 0x41dc0, 0x21c4f7, 0x70fbf5, 0x1a35e7, 0x7340e, 0x795d46, 0x1a4cd0, 0x645caf, 0x1d2668, 0x666e99, 0x6f0634, 0x7be5db, 0x455fdc, 0x530765, 0x5dc1b0, 0x7973de, 0x5cfd0a, 0x2cc93, 0x70f806, 0x189c2a, 0x49c5aa, 0x776a51, 0x3bcf2c, 0x7f234f, 0x6b16e0, 0x3c15ca, 0x155e68, 0x72f6b7, 0x1e29ce} +var DL_iroots = []int32{0x3ffe00, 0x7f7b0a, 0x7eafd, 0x27cefe, 0x78c1dd, 0xd5ed8, 0xbdee8, 0x7c41bd, 0x56fada, 0x5065b8, 0x2c04f7, 0x50458c, 0x1feb81, 0x57b53, 0x5bf6d6, 0x6401d6, 0x7b9a3c, 0x42ae00, 0x4bde, 0x650fcc, 0x320368, 0x155b09, 0x3ae519, 0x20522a, 0x202c85, 0x57e699, 0x111560, 0x86270, 0x492879, 0x107a5c, 0x703f91, 0x5649a9, 0x2ab0d3, 0x6042ad, 0x2703d0, 0x445acd, 0x44a7ae, 0x71508b, 0x77c467, 0x737c59, 0x476c75, 0x186ba4, 0x20a9e9, 0x4a5bc2, 0x3a50a7, 0x4a61e3, 0x19152a, 0x19edc3, 0x83aa3, 0x5c0965, 0x495b3, 0x49dc01, 0x2bc1bf, 0x49556b, 0x2e7184, 0x3aea7b, 0x442152, 0x26b82c, 0x36cfd4, 0x195afd, 0x4a013c, 0x50eb34, 0x7e69e1, 0x56959a, 0x454828, 0x375fa9, 0x3b3864, 0x2e115e, 0x15f7fe, 0xc66bc, 0x182f20, 0x6c41dc, 0x6b686f, 0x6bccfc, 0x2b520, 0x24c36d, 0x1c400a, 0x4fa93f, 0x3637f8, 0x7cfb95, 0x1417f8, 0x744760, 0x33821, 0x5b6a95, 0x319640, 0x66a6b9, 0x2182, 0x38d436, 0x4378a7, 0x7212bd, 0x10c942, 0x7f3301, 0x509a79, 0x781bea, 0x7bd511, 0x330417, 0x15d39e, 0x639a9e, 0x6b4a2d, 0x5d423, 0x13f609, 0x59c5, 0x12beed, 0xa3d7e, 0x25cbf7, 0x64593, 0x385bb5, 0x2d485d, 0x567162, 0x5f19c9, 0xf017b, 0x4bcf0f, 0x7df037, 0x376f20, 0x302d52, 0x30ad80, 0xf430a, 0x3e4f8e, 0x62488f, 0x13308b, 0x183045, 0x5eaa3a, 0x4ad613, 0x1629a3, 0x2e67e7, 0x381e31, 0x17537f, 0x3bf91b, 0x61b633, 0xce94a, 0x6a8199, 0x43ca37, 0x14c921, 0xbcb2, 0x4410d5, 0x875b0, 0x361a57, 0x6743d7, 0xee7fb, 0x7d136e, 0x22e2f7, 0x66c23, 0x221e51, 0x2cd89c, 0x3a8025, 0x3fa26, 0x10d9cd, 0x197168, 0x62b999, 0x1b8352, 0x659331, 0x682bb, 0x78abf3, 0x65aa1a, 0xee40c, 0x5e1b0a, 0x7bc241, 0x44deec, 0x4a1ac8, 0x2e5ec4, 0x1b73c3, 0x385e99, 0x66a867, 0x73835c, 0x51e290, 0x6735f9, 0x7d63e5, 0x309342, 0x126c59, 0x7d0b46, 0x4c7769, 0x620269, 0x28371, 0x5a6c4a, 0x5ac276, 0x1eb9a8, 0x39a1e1, 0x76cf29, 0x38d3ee, 0x276ee5, 0x1c2ea9, 0x198008, 0x2b35f4, 0x846cc, 0x4be732, 0x5dc219, 0x74041a, 0x68fbfc, 0x14fa53, 0x26da88, 0x629f68, 0x1386ad, 0x1df292, 0x4d6d7e, 0x6bd93a, 0x6e21c, 0x15d2d1, 0x32a1c2, 0x6cfee6, 0x145742, 0x10095a, 0x62d4b6, 0x635ac2, 0x2daf77, 0x362470, 0x57a770, 0x6ccb43, 0x397ae8, 0x6785bb, 0x59efb0, 0x6cd67d, 0x41fee5, 0x6c9290, 0x2785c6, 0x56ce68, 0x54811c, 0x7cc6dd, 0x65633a, 0x32ffc5, 0x4b6d1a, 0x412fe6, 0x2532bf, 0x7b7ef5, 0x7aa6e8, 0x36de3e, 0xbba6e, 0x8032a, 0x364683, 0x4ef07b, 0x60df7d, 0x2fa50a, 0x9ffdf, 0x7f904, 0xa8fc, 0x189d76, 0x78507e, 0x7360a7, 0x71ff1b, 0x6381e7, 0x7221a3, 0x30ba22, 0x1244aa, 0x395d04, 0x35b760, 0x4a44a4, 0x12db10, 0x5aba7a, 0x7bcd0c, 0x365bde, 0x255461, 0x5da206, 0x33008e, 0x459e09, 0x5c872d, 0x4be0a7, 0x5ff56e} + +func DL_round(a int32, b int32) int32 { + return (a + b/2) / b +} + +// constant time absolute vaue +func DL_nabs(x int32) int32 { + mask := (x >> 31) + return (x + mask)^mask +} + +// Montgomery stuff +func DL_redc(T uint64) int32 { + m := uint32(T) * (uint32(DL_ND)) + return int32((uint64(m)*DL_PRIME + T) >> 32) +} + +func DL_nres(x uint32) int32 { + return DL_redc(uint64(x)*DL_R2MODP) +} + +func DL_modmul(a uint32, b uint32) int32 { + return DL_redc(uint64(a)*uint64(b)) +} + +//make all elements +ve +func DL_poly_pos(p []int32) { + for i := 0; i < DL_DEGREE; i++ { + p[i] += (p[i] >> 31)&DL_PRIME + } +} + +// NTT code + +// Important! +// DL_nres(x); DL_ntt(x) +// DL_nres(y); DL_ntt(y) +// z=x*y +// DL_intt(z); +// DL_redc(z); + +// is equivalent to (note that DL_nres() and DL_redc() cancel out) + +// DL_ntt(x); +// DL_nres(y); DL_ntt(y); +// z=x*y +// DL_intt(z) + +// is equivalent to + +// DL_ntt(x) +// DL_ntt(y) +// z=x*y +// DL_intt(z) +// DL_nres(z) + +// In all cases z ends up in normal (non-Montgomery) form! +// So the conversion to Montgomery form can be "pushed" through the calculation. + +// Here DL_intt(z) <- DL_intt(z);DL_nres(z); +// Combining is more efficient +// note that DL_ntt() and DL_intt() are not mutually inverse + +/* NTT code */ +/* Cooley-Tukey NTT */ +/* Excess of 2 allowed on input - coefficients must be < 2*PRIME */ + +func DL_ntt(x []int32) { + + var start int + len := DL_DEGREE/2 + + var S, V int32 + var q int32 = DL_PRIME + + //Make positive + DL_poly_pos(x) + m := 1 + for m < DL_DEGREE { + start = 0 + for i := 0; i < m; i++ { + S = DL_roots[m+i] + for j := start; j < start+len; j++ { + V = DL_modmul(uint32(x[j+len]), uint32(S)) + x[j+len] = x[j] + 2 * q - V + x[j] = x[j] + V + } + start += 2 * len + } + len /= 2 + m *= 2 + } +} + +// Gentleman-Sande INTT +// Excess of 2 allowed on input - coefficients must be < 2*PRIME +// Output fully reduced +const NTTL = 1 + +func DL_intt(x []int32) { + var k,lim int + t := 1 + var S,U,V,W int32 + var q int32 = DL_PRIME + m := DL_DEGREE/2 + n := DL_LGN + for m >= 1 { + lim = NTTL >> n + n-- + k = 0 + for i := 0; i < m; i++ { + S = DL_iroots[m+i] + for j := k; j < k+t; j++ { + if NTTL > 1 { + if m < NTTL && j < k+lim { + U = DL_modmul(uint32(x[j]), DL_ONE) + V = DL_modmul(uint32(x[j+t]), DL_ONE) + } else { + U = x[j] + V = x[j+t] + } + } else { + U = x[j] + V = x[j+t] + } + x[j] = U + V + W = U + (DL_DEGREE/NTTL)*q - V + x[j+t] = DL_modmul(uint32(W), uint32(S)) + //T := int64(W)*int64(S) + //var M int64 = (T*DL_ND) & 0xffffffff + //R := int((M * int64(DL_PRIME+T)) >> 32) + //fmt.Printf("x,W,S= %d %d %d %x %x %d\n",x[j+t],W,S,T,M,R) + } + k += 2 * t + } + t *= 2 + m /= 2 + } + //fmt.Printf("\nx[0]= %d\n",x[0]) + //fmt.Printf("x[1]= %d\n",x[1]) + for j := 0; j < DL_DEGREE; j++ { + //fully reduce, DL_nres combined with 1/DEGREE + x[j] = DL_modmul(uint32(x[j]), DL_COMBO) + x[j] -= q + x[j] += (x[j] >> 31)&q + } +} + +func DL_nres_it(p []int32) { + for i := 0; i < DL_DEGREE; i++ { + p[i] = DL_nres(uint32(p[i])) + } +} + +func DL_redc_it(p []int32) { + for i := 0; i < DL_DEGREE; i++ { + p[i] = DL_redc(uint64(p[i])) + } +} + +//copy polynomial +func DL_poly_copy(p1 []int32, p2 []int32) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = p2[i] + } +} + +//copy from small polynomial +func DL_poly_scopy(p1 []int32, p2 []int8) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = int32(p2[i]) + } +} + +//copy from medium polynomial +func DL_poly_mcopy(p1 []int32, p2 []int16) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = int32(p2[i]) + } +} + +func DL_poly_zero(p1 []int32) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = 0 + } +} + +func DL_poly_negate(p1 []int32, p2 []int32) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = DL_PRIME - p2[i] + } +} + +func DL_poly_mul(p1 []int32, p2 []int32, p3 []int32) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = DL_modmul(uint32(p2[i]), uint32(p3[i])) + } +} + +func DL_poly_add(p1 []int32, p2 []int32, p3 []int32) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = p2[i] + p3[i] + } +} + +func DL_poly_sub(p1 []int32, p2 []int32, p3 []int32) { + for i := 0; i < DL_DEGREE; i++ { + p1[i] = p2[i] + DL_PRIME - p3[i] + } +} + +//reduce inputs that are already < 2q +func DL_poly_soft_reduce(poly []int32) { + var e int32 + for i := 0; i < DL_DEGREE; i++ { + e = poly[i] - DL_PRIME + poly[i] = e + ((e >> 31)&DL_PRIME) + + } +} + +//fully reduces modulo q +func DL_poly_hard_reduce(poly []int32) { + var e int32 + for i := 0; i < DL_DEGREE; i++ { + e = DL_modmul(uint32(poly[i]), DL_ONE) //reduces to < 2q + e = e - DL_PRIME + poly[i] = e + ((e >> 31)&DL_PRIME) //finishes it off + } +} + +//Generate A[i][j] from rho +func DL_ExpandAij(rho []byte, Aij []int32, i int, j int) { + sh := NewSHA3(SHA3_SHAKE128) + var cf int32 + //var b0, b1, b2 uint32 + var buff [4*DL_DEGREE]byte // should be plenty + + for m := 0; m < 32; m++ { + sh.Process(rho[m]) + } + sh.Process(byte(j & 0xFF)) + sh.Process(byte(i & 0xff)) + sh.Shake(buff[:], 4*DL_DEGREE) + m := 0 + n := 0 + for m < DL_DEGREE { + b0 := uint32(buff[n]&0xff) + n++ + b1 := uint32(buff[n]&0xff) + n++ + b2 := uint32(buff[n]&0xff) + n++ + cf = int32(((b2 & 0x7f) << 16) + (b1 << 8) + b0) + if cf >= DL_PRIME { + continue + } + Aij[m] = cf + m++ + } +} + +// array t has ab active bits per word +// extract bytes from array of words +// if max!=0 then -max<=t[i]<=+max +func DL_nextbyte32(ab int, max int, t []int32, position []int) byte { + ptr := position[0] // index in array + bts := position[1] // bit index in word + left := ab - bts // number of bits left in this word + i := 0 + k := ptr % 256 + var r int32 + var w int32 = t[k] + + if max != 0 { + w = int32(max) - w + } + r = w >> bts + for left < 8 { + i++ + w = t[k+i] + if max != 0 { + w = int32(max) - w + } + r |= w << left + left += ab + } + bts += 8 + for bts >= ab { + bts -= ab + ptr++ + } + position[0] = ptr + position[1] = bts + + return byte(r & 0xff) +} + +// array t has ab active bits per word +// extract dense bytes from array of words +// if max!=0 then -max<=t[i]<=+max +func DL_nextbyte16(ab int, max int, t []int16, position []int) byte { + ptr := position[0] // index in array + bts := position[1] // bit index in word + left := ab - bts // number of bits left in this word + i := 0 + k := ptr % 256 + var r int32 + var w int32 = int32(t[k]) + if max != 0 { + w = int32(max) - w + } + r = w >> bts + for left < 8 { + i++ + w = int32(t[k+i]) + if max != 0 { + w = int32(max) - w + } + r |= w << left + left += ab + } + bts += 8 + for bts >= ab { + bts -= ab + ptr++ + } + position[0] = ptr + position[1] = bts + + return byte(r & 0xff) +} + +// array t has ab active bits per word +// extract dense bytes from array of words +// if max!=0 then -max<=t[i]<=+max +func DL_nextbyte8(ab int, max int, t []int8, position []int) byte { + ptr := position[0] // index in array + bts := position[1] // bit index in word + left := ab - bts // number of bits left in this word + i := 0 + k := ptr % 256 + var r int32 + var w int32 = int32(t[k]) + if max != 0 { + w = int32(max) - w + } + r = w >> bts + for left < 8 { + i++ + w = int32(t[k+i]) + if max != 0 { + w = int32(max) - w + } + r |= w << left + left += ab + } + bts += 8 + for bts >= ab { + bts -= ab + ptr++ + } + position[0] = ptr + position[1] = bts + + return byte(r&0xff) +} + +// extract ab bits into word from dense byte stream +func DL_nextword(ab int, max int, t []byte, position []int) int32 { + ptr := position[0] // index in array + bts := position[1] // bit index in word + r := int32(t[ptr]>>bts) + mask := int32((1<= 8 { + bts -= 8 + ptr++ + } + w = r&mask + if max != 0 { + w = int32(max) - w + } + position[0] = ptr + position[1] = bts + return w +} + +//pack public key +func DL_pack_pk(params []int, pk []byte, rho []byte, t1 [][DL_DEGREE]int16) int { + var pos [2]int + pos[0] = 0; pos[1] = 0 + ck := params[3] + for i := 0; i < 32; i++ { + pk[i] = rho[i] + } + n := 32 + for j := 0; j < ck; j++ { + for i := 0; i < (DL_DEGREE*DL_TD)/8; i++ { + pk[n] = DL_nextbyte16(DL_TD, 0, t1[j][:], pos[:]) + n++ + } + } + return n +} + +//unpack public key +func DL_unpack_pk(params []int, rho []byte, t1 [][DL_DEGREE]int16, pk []byte) { + var pos [2]int + pos[0] = 32; pos[1] = 0 + ck := params[3] + for i := 0; i < 32; i++ { + rho[i] = pk[i] + } + for j := 0; j < ck; j++ { + for i := 0; i < DL_DEGREE; i++ { + t1[j][i] = int16(DL_nextword(DL_TD, 0, pk, pos[:])) + } + } +} + +// secret key of size 32*3+DEGREE*(K*D+L*LG2ETA1+K*LG2ETA1)/8 +func DL_pack_sk(params []int, sk []byte, rho []byte, bK []byte, tr []byte, s1 [][DL_DEGREE]int8, s2 [][DL_DEGREE]int8, t0 [][DL_DEGREE]int16) int { + n := 32 + ck := params[3] + el := params[4] + eta := params[5] + lg2eta1 := params[6] + + for i := 0; i < 32; i++ { + sk[i] = rho[i] + } + for i := 0; i < 32; i++ { + sk[n] = bK[i] + n++ + } + for i := 0; i < 32; i++ { + sk[n] = tr[i] + n++ + } + + var pos [2]int + pos[0] = 0; pos[1] = 0 + + for j := 0; j < el; j++ { + for i := 0; i < (DL_DEGREE*lg2eta1)/8; i++ { + sk[n] = DL_nextbyte8(lg2eta1, eta, s1[j][:], pos[:]) + n++ + } + } + pos[0] = 0; pos[1] = 0 + for j := 0; j < ck; j++ { + for i := 0; i < (DL_DEGREE*lg2eta1)/8; i++ { + sk[n] = DL_nextbyte8(lg2eta1, eta, s2[j][:], pos[:]) + n++ + } + } + pos[0] = 0; pos[1] = 0 + for j := 0; j < ck; j++ { + for i := 0; i < (DL_DEGREE*DL_D)/8; i++ { + sk[n] = DL_nextbyte16(DL_D, (1 << (DL_D - 1)), t0[j][:], pos[:]) + n++ + } + } + return n +} + +func DL_unpack_sk(params []int, rho []byte, bK []byte, tr []byte, s1 [][DL_DEGREE]int8, s2 [][DL_DEGREE]int8, t0 [][DL_DEGREE]int16, sk []byte) { + n := 32 + ck := params[3] + el := params[4] + eta := params[5] + lg2eta1 := params[6] + + for i := 0; i < 32; i++ { + rho[i] = sk[i] + } + for i := 0; i < 32; i++ { + bK[i] = sk[n] + n++ + } + for i := 0; i < 32; i++ { + tr[i] = sk[n] + n++ + } + + var pos [2]int + pos[0] = n; pos[1] = 0 + for j := 0; j < el; j++ { + for i := 0; i < DL_DEGREE; i++ { + s1[j][i] = int8(DL_nextword(lg2eta1, eta, sk, pos[:])) + } + } + //fmt.Printf("lg2eta1 = %d eta= %d\n",lg2eta1,eta) + //fmt.Printf("s1[0][0]= %d sk[0] = %d\n",s1[0][0],sk[n]) + for j := 0; j < ck; j++ { + for i := 0; i < DL_DEGREE; i++ { + s2[j][i] = int8(DL_nextword(lg2eta1, eta, sk, pos[:])) + } + } + for j := 0; j < ck; j++ { + for i := 0; i < DL_DEGREE; i++ { + t0[j][i] = int16(DL_nextword(DL_D, (1 << (DL_D - 1)), sk, pos[:])) + } + } +} + +// pack signature - change z +func DL_pack_sig(params []int, sig []byte, z [][DL_DEGREE]int32, ct []byte, h []byte) int { + lg := params[1] + gamma1 := 1 << lg + ck := params[3] + el := params[4] + omega := params[7] + + var t int32 + + for i := 0; i < 32; i++ { + sig[i] = ct[i] + } + + n := 32 + var pos [2]int + pos[0] = 0; pos[1] = 0 + //pre-process z + for i := 0; i < el; i++ { + for m := 0; m < DL_DEGREE; m++ { + t = z[i][m] + if t > DL_PRIME/2 { + t -= DL_PRIME + } + t = int32(gamma1) - t + z[i][m] = t + } + } + for j := 0; j < el; j++ { + for i := 0; i < (DL_DEGREE*(lg+1))/8; i++ { + sig[n] = DL_nextbyte32(lg+1, 0, z[j][:], pos[:]) + n++ + } + } + for i := 0; i < omega+ck; i++ { + sig[n] = h[i] + n++ + } + return n +} + +func DL_unpack_sig(params []int, z [][DL_DEGREE]int32, ct []byte, h []byte, sig []byte) { + lg := params[1] + gamma1 := 1 << lg + ck := params[3] + el := params[4] + omega := params[7] + var t int32 + m := 32 + (el*DL_DEGREE*(lg+1))/8 + + for i := 0; i < 32; i++ { + ct[i] = sig[i] + } + + var pos [2]int + pos[0] = 32; pos[1] = 0 + for j := 0; j < el; j++ { + for i := 0; i < DL_DEGREE; i++ { + t = DL_nextword(lg+1, 0, sig, pos[:]) + t = int32(gamma1)-t + if t < 0 { + t += DL_PRIME + } + z[j][i] = t + } + } + for i := 0; i < omega+ck; i++ { + h[i] = sig[m] + m++ + } +} + +// rejection sampling in range -ETA to +ETA +func DL_sample_Sn(params []int, rhod []byte, s []int8, n int) { + eta := int8(params[5]) + lg2eta1 := params[6] + sh := NewSHA3(SHA3_SHAKE256) + var buff [272]byte + + for m := 0; m < 64; m++ { + sh.Process(rhod[m]) + } + sh.Process(byte(n & 0xff)) + sh.Process(byte((n >> 8) & 0xff)) + sh.Shake(buff[:], 272) + + var pos [2]int + pos[0] = 0; pos[1] = 0 + for m := 0; m < DL_DEGREE; m++ { + for next := true; next; next = s[m] > 2*eta { + s[m] = int8(DL_nextword(lg2eta1, 0, buff[:], pos[:])) + } + s[m] = int8(eta - s[m]) + } +} + +//uniform random sampling +func DL_sample_Y(params []int, k int, rhod []byte, y [][DL_DEGREE]int32) { + lg := params[1] + gamma1 := 1 << lg + el := params[4] + var ki int + var w, t int32 + var buff [DL_YBYTES]byte + + for i := 0; i < el; i++ { + sh := NewSHA3(SHA3_SHAKE256) + for j := 0; j < 64; j++ { + sh.Process(rhod[j]) + } + ki = k + i + sh.Process(byte(ki & 0xff)) + sh.Process(byte(ki >> 8)) + sh.Shake(buff[:], DL_YBYTES) + + var pos [2]int + pos[0] = 0; pos[1] = 0 + for m := 0; m < DL_DEGREE; m++ { + //take in LG+1 bits at a time + w = DL_nextword(lg+1, 0, buff[:], pos[:]) + w = int32(gamma1) - w + t = w >> 31 + y[i][m] = w + (DL_PRIME & t) + } + } +} + +//CRH(rho,t1) +func DL_CRH1(params []int, H []byte, rho []byte, t1 [][DL_DEGREE]int16) { + var pos [2]int + pos[0] = 0; pos[1] = 0 + ck := params[3] + sh := NewSHA3(SHA3_SHAKE256) + //fmt.Printf("rho[1]= %d\n",rho[1]) + for i := 0; i < 32; i++ { + sh.Process(rho[i]) + } + for j := 0; j < ck; j++ { + //fmt.Printf("X t1[j][0]= %d\n",t1[j][0]) + //fmt.Printf("Y t1[j][1]= %d\n",t1[j][1]) + //fmt.Printf("Z t1[j][2]= %d\n",t1[j][2]) + for i := 0; i < (DL_DEGREE*DL_TD)/8; i++ { + nxt := DL_nextbyte16(DL_TD, 0, t1[j][:], pos[:]) + /* if i==0 && j==0 { + //fmt.Printf(" nxt= %d",nxt) + } + */ + sh.Process(nxt) + } + } + sh.Shake(H, 32) + //fmt.Printf("H[0]= %d\n",H[0]) +} + +//CRH(tr,M) +func DL_CRH2(H []byte, tr []byte, mess []byte, mlen int) { + sh := NewSHA3(SHA3_SHAKE256) + for i := 0; i < 32; i++ { + sh.Process(tr[i]) + } + for i := 0; i < mlen; i++ { + sh.Process(mess[i]) + } + sh.Shake(H, 64) +} + +//CRH(K,mu) +func DL_CRH3(H []byte, bK []byte, mu []byte) { + sh := NewSHA3(SHA3_SHAKE256) + for i := 0; i < 32; i++ { + sh.Process(bK[i]) + } + for i := 0; i < 64; i++ { + sh.Process(mu[i]) + } + sh.Shake(H, 64) +} + +//H(mu,w1) +func DL_H4(params []int, CT []byte, mu []byte, w1 [][DL_DEGREE]int8) { + var pos [2]int + pos[0] = 0; pos[1] = 0 + ck := params[3] + dv := params[2] + w1b := 4 + if dv == 88 { + w1b = 6 + } + + sh := NewSHA3(SHA3_SHAKE256) + for i := 0; i < 64; i++ { + sh.Process(mu[i]) + } + for j := 0; j < ck; j++ { + for i := 0; i < (DL_DEGREE*w1b)/8; i++ { + sh.Process(DL_nextbyte8(w1b, 0, w1[j][:], pos[:])) + } + } + sh.Shake(CT, 32) +} + +func DL_SampleInBall(params []int, ct []byte, c []int32) { + tau := params[0] + var signs [8]byte + var buff [136]byte + sh := NewSHA3(SHA3_SHAKE256) + + for i := 0; i < 32; i++ { + sh.Process(ct[i]) + } + sh.Shake(buff[:], 136) + + for i := 0; i < 8; i++ { + signs[i] = buff[i] + } + + k := 8 + b := 0 + DL_poly_zero(c) + var sn int = int(signs[0]) + n := 1 + var j int + + for i := DL_DEGREE - tau; i < DL_DEGREE; i++ { + for next := true; next; next = j > i { + j = int(buff[k]) + k++ + } + c[i] = c[j] + c[j] = 1 - 2*(int32(sn&1)) + sn >>= 1 + b++ + if b == 8 { + sn = int(signs[n]) + n++ + b = 0 + } + } +} + +func DL_Power2Round(t []int32, t0 []int16, t1 []int16) { + var w, d, r int32 + for m := 0; m < DL_DEGREE; m++ { + w = t[m] + d = 1 << DL_D + r = (w + d/2 - 1) >> DL_D + w -= r << DL_D + t1[m] = int16(r) + t0[m] = int16(w) + } +} + +// ALPHA = (Q-1)/16 - borrowed from dilithium ref implementation +func DL_decompose_lo(params []int, a int32) int32 { + var gamma2 int + dv := params[2] + var a0, a1 int32 + a1 = (a + 127) >> 7 + if dv == 32 { + a1 = (a1*1025 + (1 << 21)) >> 22 + a1 &= 15 + gamma2 = (DL_PRIME - 1) / 32 + } else { //88 + a1 = (a1*11275 + (1 << 23)) >> 24 + a1 ^= ((43 - a1) >> 31) & a1 + gamma2 = (DL_PRIME - 1) / 88 + } + + a0 = a - a1 * 2 * int32(gamma2) + a0 -= (((DL_PRIME-1)/2 - a0) >> 31) & DL_PRIME + a0 += (a0 >> 31) & DL_PRIME + + return a0 +} + +// ALPHA = (Q-1)/16 +func DL_decompose_hi(params []int, a int32) int8 { + dv := params[2] + var a1 int32 = (a + 127) >> 7 + + if dv == 32 { + a1 = (a1*1025 + (1 << 21)) >> 22 + a1 &= 15 + } else { + a1 = (a1*11275 + (1 << 23)) >> 24 + a1 ^= ((43 - a1) >> 31) & a1 + } + return int8(a1) +} + +func DL_lobits(params []int, r0 []int32, r []int32) { + for m := 0; m < DL_DEGREE; m++ { + r0[m] = DL_decompose_lo(params, r[m]) + } +} + +func DL_hibits(params []int, r1 []int8, r []int32) { + for m := 0; m < DL_DEGREE; m++ { + r1[m] = DL_decompose_hi(params, r[m]) + } +} + +// before h initialised to zeros, hptr=0 +// after new hptr returned and h[OMEGA+i]= hptr +func DL_MakePartialHint(params []int, h []byte, hptr int, z []int32, r []int32) int { + var a0, a1 int8 + var rz int32 + omega := params[7] + for m := 0; m < DL_DEGREE; m++ { + a0 = DL_decompose_hi(params, r[m]) + rz = r[m] + z[m] + rz -= DL_PRIME + rz = rz + ((rz >> 31) & DL_PRIME) + a1 = DL_decompose_hi(params, rz) + if a0 != a1 { + if hptr >= omega { + return omega + 1 + } + h[hptr] = byte(m) & 0xff + hptr++ + } + } + return hptr +} + +func DL_UsePartialHint(params []int, r []int8, h []byte, hptr int, i int, w []int32) int { + dv := int8(params[2]) + omega := params[7] + md := int8(dv / 2) + var a0 int32 + var a1 int8 + for m := 0; m < DL_DEGREE; m++ { + a1 = DL_decompose_hi(params, w[m]) + if m == int(h[hptr]) && hptr < int(h[omega+i]) { + hptr++ + a0 = DL_decompose_lo(params, w[m]) + if a0 <= DL_PRIME/2 { + a1++ + if a1 >= md { + a1 -= md + } + } else { + a1-- + if a1 < 0 { + a1 += md + } + } + } + r[m] = a1 + } + return hptr +} + +func DL_infinity_norm(w []int32) int32 { + var az int32 + var n int32 + n = 0 + for m := 0; m < DL_DEGREE; m++ { + az = w[m] + if az > (DL_PRIME/2) { + az = DL_PRIME - az + } + if az > n { + n = az + } + } + return n +} + +//Dilithium API +func DL_keypair(params []int, tau []byte, sk []byte, pk []byte) { + var buff [128]byte + var rho [32]byte + var rhod [64]byte + var bK [32]byte + var tr [32]byte // 320 bytes + var Aij [DL_DEGREE]int32 // 1024 bytes + var w [DL_DEGREE]int32 // work space 1024 bytes + var r [DL_DEGREE]int32 // work space 1024 bytes total = 12352 + + ck := params[3] + el := params[4] + + s1 := make([][DL_DEGREE]int8, el) // 1280 bytes + s2 := make([][DL_DEGREE]int8, ck) // 1536 bytes + t0 := make([][DL_DEGREE]int16, ck) // 3072 bytes + t1 := make([][DL_DEGREE]int16, ck) // 3072 bytes + + sh := NewSHA3(SHA3_SHAKE256) + + for i := 0; i < 32; i++ { + sh.Process(tau[i]) + } + sh.Shake(buff[:], 128) + + for i := 0; i < 32; i++ { + rho[i] = buff[i] + bK[i] = buff[i+96] + } + + for i := 0; i < 64; i++ { + rhod[i] = buff[32+i] + } + //fmt.Printf("rhod[0]= %d\n", rhod[0]) + + for i := 0; i < el; i++ { + DL_sample_Sn(params, rhod[:], s1[i][:], i) + } + //fmt.Printf("s1[0][0]= %d\n",s1[0][0]) + + for i := 0; i < ck; i++ { + DL_sample_Sn(params, rhod[:], s2[i][:], el+i) + //fmt.Printf("s2[0][0]= %d\n",s2[0][0]) + DL_poly_zero(r[:]) + for j := 0; j < el; j++ { + DL_poly_scopy(w[:], s1[j][:]) + DL_ntt(w[:]) + DL_ExpandAij(rho[:], Aij[:], i, j) //This is bottleneck + DL_poly_mul(w[:], w[:], Aij[:]) + DL_poly_add(r[:], r[:], w[:]) + //DL_poly_soft_reduce(r[:]) // be lazy + } + DL_poly_hard_reduce(r[:]) + /*for k:=0; k= gamma1-beta { //seems to be always true + badone = true; + break; + } + } + if badone { + continue + } + // Calculate Ay=w-c.s2 and r0=DL_lobits(w-c.s2) + nh = 0 + for i := 0; i < omega+ck; i++ { + hint[i] = 0 + } + for i := 0; i < ck; i++ { + DL_poly_scopy(w[:], s2[i][:]) + DL_ntt(w[:]) + DL_poly_mul(w[:], w[:], c[:]) + + DL_intt(w[:]) + DL_poly_sub(Ay[i][:], Ay[i][:], w[:]) + DL_poly_soft_reduce(Ay[i][:]) // Ay=w-cs2 + DL_lobits(params, w[:], Ay[i][:]) // r0 + if DL_infinity_norm(w[:]) >= gamma2-beta { + badone = true + break + } + + DL_poly_mcopy(w[:], t0[i][:]) + DL_ntt(w[:]) + DL_poly_mul(w[:], w[:], c[:]) + + DL_intt(w[:]) + DL_poly_negate(r[:], w[:]) // -ct0 + if DL_infinity_norm(r[:]) >= gamma2 { + badone = true + break + } + DL_poly_sub(Ay[i][:], Ay[i][:], r[:]) + DL_poly_soft_reduce(Ay[i][:]) + + nh = DL_MakePartialHint(params, hint[:], nh, r[:], Ay[i][:]) + if nh > omega { + badone = true + break + } + hint[omega+i] = byte(nh) + } + if badone { + continue + } + break + } + //fmt.Printf("y[0][0] = %d y[0][1] = %d\n",y[0][0],y[0][1]) + DL_pack_sig(params, sig, y[:], ct[:], hint[:]) + return k + 1 +} + +func DL_verify(params []int, pk []byte, M []byte, sig []byte) bool { + var rho [32]byte + var mu [64]byte + var ct [32]byte + var cct [32]byte + var tr [32]byte // 192 bytes + var hint [100]byte + + var Aij [DL_DEGREE]int32 // 1024 bytes + var c [DL_DEGREE]int32 // 1024 bytes + var w [DL_DEGREE]int32 // work space // 1024 bytes + var r [DL_DEGREE]int32 // work space // 1024 bytes total=14077 bytes + + ck := params[3] + el := params[4] + + z := make([][DL_DEGREE]int32, el) + t1 := make([][DL_DEGREE]int16, ck) + w1d := make([][DL_DEGREE]int8, ck) + + tau := params[0] + lg := params[1] + gamma1 := int32(1<= gamma1-beta { + return false + } + DL_ntt(z[i][:]) // convert to ntt form + } + + DL_CRH1(params, tr[:], rho[:], t1) + DL_CRH2(mu[:], tr[:], M, len(M)) + DL_SampleInBall(params, ct[:], c[:]) + DL_ntt(c[:]) + + // Calculate Az + hints := 0 + for i := 0; i < ck; i++ { + DL_poly_zero(r[:]) + for j := 0; j < el; j++ { + //Note : no NTTs in here + DL_poly_copy(w[:], z[j][:]) + DL_ExpandAij(rho[:], Aij[:], i, j) + DL_poly_mul(w[:], w[:], Aij[:]) + DL_poly_add(r[:], r[:], w[:]) + //DL_poly_soft_reduce(r[:]) // be lazy + } + DL_poly_hard_reduce(r[:]) + + // Calculate Az-ct1.s^d + for m := 0; m < DL_DEGREE; m++ { + w[m] = int32(t1[i][m])< omega { + return false + } + } + + DL_H4(params, cct[:], mu[:], w1d) + + for i := 0; i < 32; i++ { + if ct[i] != cct[i] { + return false + } + } + return true +} + +func DL_keypair_2(tau []byte, sk []byte, pk []byte) { + DL_keypair(DL_PARAMS_2[:], tau, sk, pk) +} + +func DL_signature_2(sk []byte, M []byte, sig []byte) int { + return DL_signature(DL_PARAMS_2[:], sk, M, sig) +} + +func DL_verify_2(pk []byte, M []byte, sig []byte) bool { + return DL_verify(DL_PARAMS_2[:], pk, M, sig) +} + +func DL_keypair_3(tau []byte, sk []byte, pk []byte) { + DL_keypair(DL_PARAMS_3[:], tau, sk, pk) +} + +func DL_signature_3(sk []byte, M []byte, sig []byte) int { + return DL_signature(DL_PARAMS_3[:], sk, M, sig) +} + +func DL_verify_3(pk []byte, M []byte, sig []byte) bool { + return DL_verify(DL_PARAMS_3[:], pk, M, sig) +} + +func DL_keypair_5(tau []byte, sk []byte, pk []byte) { + DL_keypair(DL_PARAMS_5[:], tau, sk, pk) +} + +func DL_signature_5(sk []byte, M []byte, sig []byte) int { + return DL_signature(DL_PARAMS_5[:], sk, M, sig) +} + +func DL_verify_5(pk []byte, M []byte, sig []byte) bool { + return DL_verify(DL_PARAMS_5[:], pk, M, sig) +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH.go index ac4c60d35d7..a341b0a5263 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH_32.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH_32.go new file mode 100644 index 00000000000..0b6cd3ac420 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ARCH_32.go @@ -0,0 +1,29 @@ +//go:build 386 || arm + +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* core BIG number class */ + +package FP256BN + +type Chunk int32 +type DChunk int64 + +const CHUNK int = 32 /* Set word size */ diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG.go index b81fadc84c6..5e446d0c687 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * @@ -21,11 +23,12 @@ package FP256BN -import "strconv" -import "math/bits" -import "github.com/hyperledger/fabric-amcl/core" - +import ( + "math/bits" + "strconv" + "github.com/hyperledger/fabric-amcl/core" +) type BIG struct { w [NLEN]Chunk @@ -64,15 +67,15 @@ func sqr(a *BIG) *DBIG { for i := 0; i < NLEN; i++ { carry = 0 for j := i + 1; j < NLEN; j++ { -//if a.w[i]<0 {fmt.Printf("Negative m i in sqr\n")} -//if a.w[j]<0 {fmt.Printf("Negative m j in sqr\n")} + //if a.w[i]<0 {fmt.Printf("Negative m i in sqr\n")} + //if a.w[j]<0 {fmt.Printf("Negative m j in sqr\n")} carry, c.w[i+j] = muladd(2*a.w[i], a.w[j], carry, c.w[i+j]) } c.w[NLEN+i] = carry } for i := 0; i < NLEN; i++ { -//if a.w[i]<0 {fmt.Printf("Negative m s in sqr\n")} + //if a.w[i]<0 {fmt.Printf("Negative m s in sqr\n")} top, bot := muladd(a.w[i], a.w[i], 0, c.w[2*i]) c.w[2*i] = bot @@ -99,8 +102,8 @@ func monty(md *BIG, mc Chunk, d *DBIG) *BIG { carry = 0 for j := 0; j < NLEN; j++ { carry, d.w[i+j] = muladd(m, md.w[j], carry, d.w[i+j]) -//if m<0 {fmt.Printf("Negative m in monty\n")} -//if md.w[j]<0 {fmt.Printf("Negative m in monty\n")} + //if m<0 {fmt.Printf("Negative m in monty\n")} + //if md.w[j]<0 {fmt.Printf("Negative m in monty\n")} } d.w[NLEN+i] += carry } @@ -116,13 +119,14 @@ func monty(md *BIG, mc Chunk, d *DBIG) *BIG { /* set this[i]+=x*y+c, and return high part */ func muladd(a Chunk, b Chunk, c Chunk, r Chunk) (Chunk, Chunk) { - tp,bt := bits.Mul64(uint64(a),uint64(b)) // use math/bits intrinsic - bot := Chunk(bt&uint64(BMASK)) - top := Chunk((tp << (64-BASEBITS)) | (bt >> BASEBITS)) - bot += c; bot += r - carry := bot>>BASEBITS + tp, bt := bits.Mul64(uint64(a), uint64(b)) // use math/bits intrinsic + bot := Chunk(bt & uint64(BMASK)) + top := Chunk((tp << (64 - BASEBITS)) | (bt >> BASEBITS)) + bot += c + bot += r + carry := bot >> BASEBITS bot &= BMASK - top+=carry + top += carry return top, bot } @@ -216,11 +220,11 @@ func NewBIGdcopy(x *DBIG) *BIG { /* test for zero */ func (r *BIG) iszilch() bool { - d:=Chunk(0) + d := Chunk(0) for i := 0; i < NLEN; i++ { - d|=r.w[i] + d |= r.w[i] } - return (1 & ((d-1)>>BASEBITS)) != 0 + return (1 & ((d - 1) >> BASEBITS)) != 0 } /* set to zero */ @@ -232,11 +236,11 @@ func (r *BIG) zero() { /* Test for equal to one */ func (r *BIG) isunity() bool { - d:=Chunk(0) + d := Chunk(0) for i := 1; i < NLEN; i++ { - d|=r.w[i] + d |= r.w[i] } - return (1 & ((d-1)>>BASEBITS) & (((r.w[0]^1)-1)>>BASEBITS)) != 0 + return (1 & ((d - 1) >> BASEBITS) & (((r.w[0] ^ 1) - 1) >> BASEBITS)) != 0 } /* set to one */ @@ -262,23 +266,39 @@ func (r *BIG) dcopy(x *DBIG) { } /* Conditional swap of two bigs depending on d using XOR - no branches */ -func (r *BIG) cswap(b *BIG, d int) { - c := Chunk(d) - c = ^(c - 1) - +func (r *BIG) cswap(b *BIG, d int) Chunk { + c := Chunk(-d) + s := Chunk(0) + v := r.w[0] ^ b.w[1] + va := v + v + va >>= 1 for i := 0; i < NLEN; i++ { t := c & (r.w[i] ^ b.w[i]) - r.w[i] ^= t - b.w[i] ^= t + t ^= v + e := r.w[i] ^ t + s ^= e // to force calculation of e + r.w[i] = e ^ va + e = b.w[i] ^ t + s ^= e + b.w[i] = e ^ va } + return s } -func (r *BIG) cmove(g *BIG, d int) { +func (r *BIG) cmove(g *BIG, d int) Chunk { b := Chunk(-d) - + s := Chunk(0) + v := r.w[0] ^ g.w[1] + va := v + v + va >>= 1 for i := 0; i < NLEN; i++ { - r.w[i] ^= (r.w[i] ^ g.w[i]) & b + t := (r.w[i] ^ g.w[i]) & b + t ^= v + e := r.w[i] ^ t + s ^= e + r.w[i] = e ^ va } + return s } /* general shift right */ @@ -396,8 +416,8 @@ func (r *BIG) pxmul(c int) *DBIG { carry := Chunk(0) for j := 0; j < NLEN; j++ { carry, m.w[j] = muladd(r.w[j], Chunk(c), carry, m.w[j]) -//if c<0 {fmt.Printf("Negative c in pxmul\n")} -//if r.w[j]<0 {fmt.Printf("Negative c in pxmul\n")} + //if c<0 {fmt.Printf("Negative c in pxmul\n")} + //if r.w[j]<0 {fmt.Printf("Negative c in pxmul\n")} } m.w[NLEN] = carry return m @@ -447,8 +467,8 @@ func (r *BIG) pmul(c int) Chunk { ak := r.w[i] r.w[i] = 0 carry, r.w[i] = muladd(ak, Chunk(c), carry, r.w[i]) -//if c<0 {fmt.Printf("Negative c in pmul\n")} -//if ak<0 {fmt.Printf("Negative c in pmul\n")} + //if c<0 {fmt.Printf("Negative c in pmul\n")} + //if ak<0 {fmt.Printf("Negative c in pmul\n")} } return carry } @@ -466,7 +486,7 @@ func (r *BIG) tobytearray(b []byte, n int) { } /* convert from byte array to BIG */ -func frombytearray(b []byte, n int) *BIG { +func BIG_frombytearray(b []byte, n int) *BIG { m := NewBIG() l := len(b) for i := 0; i < int(MODBYTES); i++ { @@ -485,7 +505,7 @@ func (r *BIG) ToBytes(b []byte) { } func FromBytes(b []byte) *BIG { - return frombytearray(b, 0) + return BIG_frombytearray(b, 0) } /* divide by 3 */ @@ -518,13 +538,13 @@ func smul(a *BIG, b *BIG) *BIG { /* Compare a and b, return 0 if a==b, -1 if ab. Inputs must be normalised */ func Comp(a *BIG, b *BIG) int { - gt:=Chunk(0) - eq:=Chunk(1) + gt := Chunk(0) + eq := Chunk(1) for i := NLEN - 1; i >= 0; i-- { - gt |= ((b.w[i]-a.w[i]) >> BASEBITS) & eq - eq &= ((b.w[i]^a.w[i])-1) >> BASEBITS + gt |= ((b.w[i] - a.w[i]) >> BASEBITS) & eq + eq &= ((b.w[i] ^ a.w[i]) - 1) >> BASEBITS } - return int(gt+gt+eq-1) + return int(gt + gt + eq - 1) } /* return parity */ @@ -534,10 +554,11 @@ func (r *BIG) parity() int { /* return n-th bit */ func (r *BIG) bit(n int) int { - if (r.w[n/int(BASEBITS)] & (Chunk(1) << (uint(n) % BASEBITS))) > 0 { - return 1 - } - return 0 + return int((r.w[n/int(BASEBITS)] & (Chunk(1) << (uint(n) % BASEBITS))) >> (uint(n) % BASEBITS)) + // if (r.w[n/int(BASEBITS)] & (Chunk(1) << (uint(n) % BASEBITS))) > 0 { + // return 1 + // } + // return 0 } /* return n last bits */ @@ -597,71 +618,78 @@ func (r *BIG) invmod2m() { r.norm() } -/* reduce this mod m */ -func (r *BIG) Mod(m1 *BIG) { - m := NewBIGcopy(m1) +func (r *BIG) ctmod(m *BIG, bd uint) { + k := bd sr := NewBIG() + c := NewBIGcopy(m) r.norm() - if Comp(r, m) < 0 { - return - } - - m.fshl(1) - k := 1 - for Comp(r, m) >= 0 { - m.fshl(1) - k++ - } + c.shl(k) - for k > 0 { - m.fshr(1) + for { sr.copy(r) - sr.sub(m) + sr.sub(c) sr.norm() r.cmove(sr, int(1-((sr.w[NLEN-1]>>uint(CHUNK-1))&1))) + if k == 0 { + break + } + c.fshr(1) + k -= 1 + } +} - k-- +/* reduce this mod m */ +func (r *BIG) Mod(m *BIG) { + k := r.nbits() - m.nbits() + if k < 0 { + k = 0 } + r.ctmod(m, uint(k)) } -/* divide this by m */ -func (r *BIG) div(m1 *BIG) { - m := NewBIGcopy(m1) - var d int - k := 0 - r.norm() - sr := NewBIG() +func (r *BIG) ctdiv(m *BIG, bd uint) { + k := bd e := NewBIGint(1) - b := NewBIGcopy(r) + sr := NewBIG() + a := NewBIGcopy(r) + c := NewBIGcopy(m) + r.norm() r.zero() - for Comp(b, m) >= 0 { - e.fshl(1) - m.fshl(1) - k++ - } + c.shl(k) + e.shl(k) - for k > 0 { - m.fshr(1) - e.fshr(1) - - sr.copy(b) - sr.sub(m) + for { + sr.copy(a) + sr.sub(c) sr.norm() - d = int(1 - ((sr.w[NLEN-1] >> uint(CHUNK-1)) & 1)) - b.cmove(sr, d) + d := int(1 - ((sr.w[NLEN-1] >> uint(CHUNK-1)) & 1)) + a.cmove(sr, d) sr.copy(r) sr.add(e) sr.norm() r.cmove(sr, d) + if k == 0 { + break + } + c.fshr(1) + e.fshr(1) + k -= 1 + } +} - k-- +/* divide this by m */ +func (r *BIG) div(m *BIG) { + k := r.nbits() - m.nbits() + if k < 0 { + k = 0 } + r.ctdiv(m, uint(k)) } /* get 8*MODBYTES size random number */ -func random(rng *core.RAND) *BIG { +func Random(rng *core.RAND) *BIG { m := NewBIG() var j int = 0 var r byte = 0 @@ -719,7 +747,7 @@ func Modmul(a1, b1, m *BIG) *BIG { a.Mod(m) b.Mod(m) d := mul(a, b) - return d.Mod(m) + return d.ctmod(m, uint(m.nbits())) } /* return a^2 mod m */ @@ -727,7 +755,7 @@ func Modsqr(a1, m *BIG) *BIG { a := NewBIGcopy(a1) a.Mod(m) d := sqr(a) - return d.Mod(m) + return d.ctmod(m, uint(m.nbits())) } /* return -a mod m */ @@ -735,7 +763,7 @@ func Modneg(a1, m *BIG) *BIG { a := NewBIGcopy(a1) a.Mod(m) a.rsub(m) - a.Mod(m) + a.norm() return a } @@ -745,8 +773,9 @@ func Modadd(a1, b1, m *BIG) *BIG { b := NewBIGcopy(b1) a.Mod(m) b.Mod(m) - a.add(b); a.norm() - a.Mod(m) + a.add(b) + a.norm() + a.ctmod(m, 1) return a } @@ -810,7 +839,7 @@ func (r *BIG) Invmodp(p *BIG) { u.fshr(1) t.copy(x1) t.add(p) - x1.cmove(t,x1.parity()) + x1.cmove(t, x1.parity()) x1.norm() x1.fshr(1) } @@ -818,7 +847,7 @@ func (r *BIG) Invmodp(p *BIG) { v.fshr(1) t.copy(x2) t.add(p) - x2.cmove(t,x2.parity()) + x2.cmove(t, x2.parity()) x2.norm() x2.fshr(1) } @@ -827,7 +856,7 @@ func (r *BIG) Invmodp(p *BIG) { u.norm() t.copy(x1) t.add(p) - x1.cmove(t,(Comp(x1,x2)>>1)&1) + x1.cmove(t, (Comp(x1, x2)>>1)&1) x1.sub(x2) x1.norm() } else { @@ -835,13 +864,13 @@ func (r *BIG) Invmodp(p *BIG) { v.norm() t.copy(x2) t.add(p) - x2.cmove(t,(Comp(x2,x1)>>1)&1) + x2.cmove(t, (Comp(x2, x1)>>1)&1) x2.sub(x1) x2.norm() } } r.copy(x1) - r.cmove(x2,Comp(u,one)&1) + r.cmove(x2, Comp(u, one)&1) } /* return this^e mod m */ diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG_32.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG_32.go new file mode 100644 index 00000000000..fda12d10c88 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BIG_32.go @@ -0,0 +1,1023 @@ +//go:build 386 || arm + +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* core BIG number class */ + +package FP256BN + +import ( + "strconv" + + "github.com/hyperledger/fabric-amcl/core" +) + +type BIG struct { + w [NLEN]Chunk +} + +type DBIG struct { + w [2 * NLEN]Chunk +} + +/***************** 32-bit specific code ****************/ + +/* First the 32/64-bit dependent BIG code */ +/* Note that because of the lack of a 128-bit integer, 32 and 64-bit code needs to be done differently */ + +/* return a*b as DBIG */ +func mul(a *BIG, b *BIG) *DBIG { + c := NewDBIG() + + // BIGMULS+=1; + + var d [NLEN]DChunk + + for i := 0; i < NLEN; i++ { + d[i] = DChunk(a.w[i]) * DChunk(b.w[i]) + } + s := d[0] + t := s + c.w[0] = Chunk(t) & BMASK + co := t >> BASEBITS + + for k := 1; k < NLEN; k++ { + s += d[k] + t = co + s + for i := k; i >= 1+k/2; i-- { + t += DChunk(a.w[i]-a.w[k-i]) * DChunk(b.w[k-i]-b.w[i]) + } + c.w[k] = Chunk(t) & BMASK + co = t >> BASEBITS + } + + for k := NLEN; k < 2*NLEN-1; k++ { + s -= d[k-NLEN] + t = co + s + for i := NLEN - 1; i >= 1+k/2; i-- { + t += DChunk(a.w[i]-a.w[k-i]) * DChunk(b.w[k-i]-b.w[i]) + } + c.w[k] = Chunk(t) & BMASK + co = t >> BASEBITS + } + c.w[2*NLEN-1] = Chunk(co) + + return c +} + +/* return a^2 as DBIG */ +func sqr(a *BIG) *DBIG { + c := NewDBIG() + // BIGSQRS+=1; + t := DChunk(a.w[0]) * DChunk(a.w[0]) + c.w[0] = Chunk(t) & BMASK + co := t >> BASEBITS + + for j := 1; j < NLEN-1; { + t = DChunk(a.w[j]) * DChunk(a.w[0]) + for i := 1; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + t = DChunk(a.w[j]) * DChunk(a.w[0]) + for i := 1; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + t += DChunk(a.w[j/2]) * DChunk(a.w[j/2]) + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + } + + for j := NLEN - 1 + (NLEN % 2); j < DNLEN-3; { + t = DChunk(a.w[NLEN-1]) * DChunk(a.w[j-NLEN+1]) + for i := j - NLEN + 2; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + t = DChunk(a.w[NLEN-1]) * DChunk(a.w[j-NLEN+1]) + for i := j - NLEN + 2; i < (j+1)/2; i++ { + t += DChunk(a.w[j-i]) * DChunk(a.w[i]) + } + t += t + t += co + t += DChunk(a.w[j/2]) * DChunk(a.w[j/2]) + c.w[j] = Chunk(t) & BMASK + co = t >> BASEBITS + j++ + } + + t = DChunk(a.w[NLEN-2]) * DChunk(a.w[NLEN-1]) + t += t + t += co + c.w[DNLEN-3] = Chunk(t) & BMASK + co = t >> BASEBITS + + t = DChunk(a.w[NLEN-1])*DChunk(a.w[NLEN-1]) + co + c.w[DNLEN-2] = Chunk(t) & BMASK + co = t >> BASEBITS + c.w[DNLEN-1] = Chunk(co) + + return c +} + +func monty(m *BIG, mc Chunk, d *DBIG) *BIG { + var dd [NLEN]DChunk + + var v [NLEN]Chunk + b := NewBIG() + + t := DChunk(d.w[0]) + v[0] = (Chunk(t) * mc) & BMASK + t += DChunk(v[0]) * DChunk(m.w[0]) + c := (t >> BASEBITS) + DChunk(d.w[1]) + s := DChunk(0) + + for k := 1; k < NLEN; k++ { + t = c + s + DChunk(v[0])*DChunk(m.w[k]) + for i := k - 1; i > k/2; i-- { + t += DChunk(v[k-i]-v[i]) * DChunk(m.w[i]-m.w[k-i]) + } + v[k] = (Chunk(t) * mc) & BMASK + t += DChunk(v[k]) * DChunk(m.w[0]) + c = (t >> BASEBITS) + DChunk(d.w[k+1]) + dd[k] = DChunk(v[k]) * DChunk(m.w[k]) + s += dd[k] + } + for k := NLEN; k < 2*NLEN-1; k++ { + t = c + s + for i := NLEN - 1; i >= 1+k/2; i-- { + t += DChunk(v[k-i]-v[i]) * DChunk(m.w[i]-m.w[k-i]) + } + b.w[k-NLEN] = Chunk(t) & BMASK + c = (t >> BASEBITS) + DChunk(d.w[k+1]) + s -= dd[k-NLEN+1] + } + b.w[NLEN-1] = Chunk(c) & BMASK + return b +} + +/* set this[i]+=x*y+c, and return high part */ +func muladd(a Chunk, b Chunk, c Chunk, r Chunk) (Chunk, Chunk) { + var prod = DChunk(a)*DChunk(b) + DChunk(c) + DChunk(r) + bot := Chunk(prod) & BMASK + top := Chunk(prod >> BASEBITS) + return top, bot +} + +/***************************************************************************/ + +func (r *BIG) get(i int) Chunk { + return r.w[i] +} + +func (r *BIG) set(i int, x Chunk) { + r.w[i] = x +} + +func (r *BIG) xortop(x Chunk) { + r.w[NLEN-1] ^= x +} + +/* normalise BIG - force all digits < 2^BASEBITS */ +func (r *BIG) norm() Chunk { + carry := Chunk(0) + for i := 0; i < NLEN-1; i++ { + d := r.w[i] + carry + r.w[i] = d & BMASK + carry = d >> BASEBITS + } + r.w[NLEN-1] = (r.w[NLEN-1] + carry) + return (r.w[NLEN-1] >> ((8 * MODBYTES) % BASEBITS)) +} + +/* Shift right by less than a word */ +func (r *BIG) fshr(k uint) int { + w := r.w[0] & ((Chunk(1) << k) - 1) /* shifted out part */ + for i := 0; i < NLEN-1; i++ { + r.w[i] = (r.w[i] >> k) | ((r.w[i+1] << (BASEBITS - k)) & BMASK) + } + r.w[NLEN-1] = r.w[NLEN-1] >> k + return int(w) +} + +/* Shift right by less than a word */ +func (r *BIG) fshl(k uint) int { + r.w[NLEN-1] = (r.w[NLEN-1] << k) | (r.w[NLEN-2] >> (BASEBITS - k)) + for i := NLEN - 2; i > 0; i-- { + r.w[i] = ((r.w[i] << k) & BMASK) | (r.w[i-1] >> (BASEBITS - k)) + } + r.w[0] = (r.w[0] << k) & BMASK + return int(r.w[NLEN-1] >> ((8 * MODBYTES) % BASEBITS)) /* return excess - only used in ff.c */ +} + +func NewBIG() *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = 0 + } + return b +} + +func NewBIGints(x [NLEN]Chunk) *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = x[i] + } + return b +} + +func NewBIGint(x int) *BIG { + b := new(BIG) + b.w[0] = Chunk(x) + for i := 1; i < NLEN; i++ { + b.w[i] = 0 + } + return b +} + +func NewBIGcopy(x *BIG) *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = x.w[i] + } + return b +} + +func NewBIGdcopy(x *DBIG) *BIG { + b := new(BIG) + for i := 0; i < NLEN; i++ { + b.w[i] = x.w[i] + } + return b +} + +/* test for zero */ +func (r *BIG) iszilch() bool { + d := Chunk(0) + for i := 0; i < NLEN; i++ { + d |= r.w[i] + } + return (1 & ((d - 1) >> BASEBITS)) != 0 +} + +/* set to zero */ +func (r *BIG) zero() { + for i := 0; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* Test for equal to one */ +func (r *BIG) isunity() bool { + d := Chunk(0) + for i := 1; i < NLEN; i++ { + d |= r.w[i] + } + return (1 & ((d - 1) >> BASEBITS) & (((r.w[0] ^ 1) - 1) >> BASEBITS)) != 0 +} + +/* set to one */ +func (r *BIG) one() { + r.w[0] = 1 + for i := 1; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* Copy from another BIG */ +func (r *BIG) copy(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = x.w[i] + } +} + +/* Copy from another DBIG */ +func (r *BIG) dcopy(x *DBIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = x.w[i] + } +} + +/* Conditional swap of two bigs depending on d using XOR - no branches */ +func (r *BIG) cswap(b *BIG, d int) Chunk { + c := Chunk(-d) + s := Chunk(0) + v := r.w[0] ^ b.w[1] + va := v + v + va >>= 1 + for i := 0; i < NLEN; i++ { + t := c & (r.w[i] ^ b.w[i]) + t ^= v + e := r.w[i] ^ t + s ^= e // to force calculation of e + r.w[i] = e ^ va + e = b.w[i] ^ t + s ^= e + b.w[i] = e ^ va + } + return s +} + +func (r *BIG) cmove(g *BIG, d int) Chunk { + b := Chunk(-d) + s := Chunk(0) + v := r.w[0] ^ g.w[1] + va := v + v + va >>= 1 + for i := 0; i < NLEN; i++ { + t := (r.w[i] ^ g.w[i]) & b + t ^= v + e := r.w[i] ^ t + s ^= e + r.w[i] = e ^ va + } + return s +} + +/* general shift right */ +func (r *BIG) shr(k uint) { + n := (k % BASEBITS) + m := int(k / BASEBITS) + for i := 0; i < NLEN-m-1; i++ { + r.w[i] = (r.w[m+i] >> n) | ((r.w[m+i+1] << (BASEBITS - n)) & BMASK) + } + r.w[NLEN-m-1] = r.w[NLEN-1] >> n + for i := NLEN - m; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* general shift left */ +func (r *BIG) shl(k uint) { + n := k % BASEBITS + m := int(k / BASEBITS) + + r.w[NLEN-1] = (r.w[NLEN-1-m] << n) + if NLEN >= m+2 { + r.w[NLEN-1] |= (r.w[NLEN-m-2] >> (BASEBITS - n)) + } + for i := NLEN - 2; i > m; i-- { + r.w[i] = ((r.w[i-m] << n) & BMASK) | (r.w[i-m-1] >> (BASEBITS - n)) + } + r.w[m] = (r.w[0] << n) & BMASK + for i := 0; i < m; i++ { + r.w[i] = 0 + } +} + +/* return number of bits */ +func (r *BIG) nbits() int { + t := NewBIGcopy(r) + k := NLEN - 1 + t.norm() + for k >= 0 && t.w[k] == 0 { + k-- + } + if k < 0 { + return 0 + } + bts := int(BASEBITS) * k + c := t.w[k] + for c != 0 { + c /= 2 + bts++ + } + return bts +} + +func (r *BIG) Nbits() int { + return r.nbits() +} + +/* Convert to Hex String */ +func (r *BIG) ToString() string { + s := "" + len := r.nbits() + + if len%4 == 0 { + len /= 4 + } else { + len /= 4 + len++ + + } + MB := int(MODBYTES * 2) + if len < MB { + len = MB + } + + for i := len - 1; i >= 0; i-- { + b := NewBIGcopy(r) + + b.shr(uint(i * 4)) + s += strconv.FormatInt(int64(b.w[0]&15), 16) + } + return s +} + +func (r *BIG) add(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = r.w[i] + x.w[i] + } +} + +func (r *BIG) or(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = r.w[i] | x.w[i] + } +} + +/* return this+x */ +func (r *BIG) Plus(x *BIG) *BIG { + s := new(BIG) + for i := 0; i < NLEN; i++ { + s.w[i] = r.w[i] + x.w[i] + } + s.norm() + return s +} + +/* this+=x, where x is int */ +func (r *BIG) inc(x int) { + r.norm() + r.w[0] += Chunk(x) +} + +/* this*=c and catch overflow in DBIG */ +func (r *BIG) pxmul(c int) *DBIG { + m := NewDBIG() + carry := Chunk(0) + for j := 0; j < NLEN; j++ { + carry, m.w[j] = muladd(r.w[j], Chunk(c), carry, m.w[j]) + } + m.w[NLEN] = carry + return m +} + +/* return this-x */ +func (r *BIG) Minus(x *BIG) *BIG { + d := new(BIG) + for i := 0; i < NLEN; i++ { + d.w[i] = r.w[i] - x.w[i] + } + return d +} + +/* this-=x */ +func (r *BIG) sub(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = r.w[i] - x.w[i] + } +} + +/* reverse subtract this=x-this */ +func (r *BIG) rsub(x *BIG) { + for i := 0; i < NLEN; i++ { + r.w[i] = x.w[i] - r.w[i] + } +} + +/* this-=x, where x is int */ +func (r *BIG) dec(x int) { + r.norm() + r.w[0] -= Chunk(x) +} + +/* this*=x, where x is small intNEXCESS */ +func (r *BIG) pmul(c int) Chunk { + carry := Chunk(0) + // r.norm(); + for i := 0; i < NLEN; i++ { + ak := r.w[i] + r.w[i] = 0 + carry, r.w[i] = muladd(ak, Chunk(c), carry, r.w[i]) + } + return carry +} + +/* convert this BIG to byte array */ +func (r *BIG) tobytearray(b []byte, n int) { + //r.norm(); + c := NewBIGcopy(r) + c.norm() + for i := int(MODBYTES) - 1; i >= 0; i-- { + b[i+n] = byte(c.w[0]) + c.fshr(8) + } +} + +/* convert from byte array to BIG */ +func BIG_frombytearray(b []byte, n int) *BIG { + m := NewBIG() + l := len(b) + for i := 0; i < int(MODBYTES); i++ { + m.fshl(8) + if i < l { + m.w[0] += Chunk(int(b[i+n] & 0xff)) + } else { + m.w[0] += Chunk(int(0 & 0xff)) + } + } + return m +} + +func (r *BIG) ToBytes(b []byte) { + r.tobytearray(b, 0) +} + +func FromBytes(b []byte) *BIG { + return BIG_frombytearray(b, 0) +} + +/* divide by 3 */ +func (r *BIG) div3() int { + carry := Chunk(0) + r.norm() + base := (Chunk(1) << BASEBITS) + for i := NLEN - 1; i >= 0; i-- { + ak := (carry*base + r.w[i]) + r.w[i] = ak / 3 + carry = ak % 3 + } + return int(carry) +} + +/* return a*b where result fits in a BIG */ +func smul(a *BIG, b *BIG) *BIG { + carry := Chunk(0) + c := NewBIG() + for i := 0; i < NLEN; i++ { + carry = 0 + for j := 0; j < NLEN; j++ { + if i+j < NLEN { + carry, c.w[i+j] = muladd(a.w[i], b.w[j], carry, c.w[i+j]) + } + } + } + return c +} + +/* Compare a and b, return 0 if a==b, -1 if ab. Inputs must be normalised */ +func Comp(a *BIG, b *BIG) int { + gt := Chunk(0) + eq := Chunk(1) + for i := NLEN - 1; i >= 0; i-- { + gt |= ((b.w[i] - a.w[i]) >> BASEBITS) & eq + eq &= ((b.w[i] ^ a.w[i]) - 1) >> BASEBITS + } + return int(gt + gt + eq - 1) +} + +/* return parity */ +func (r *BIG) parity() int { + return int(r.w[0] % 2) +} + +/* return n-th bit */ +func (r *BIG) bit(n int) int { + return int((r.w[n/int(BASEBITS)] & (Chunk(1) << (uint(n) % BASEBITS))) >> (uint(n) % BASEBITS)) + // if (r.w[n/int(BASEBITS)] & (Chunk(1) << (uint(n) % BASEBITS))) > 0 { + // return 1 + // } + // return 0 +} + +/* return n last bits */ +func (r *BIG) lastbits(n int) int { + msk := (1 << uint(n)) - 1 + r.norm() + return (int(r.w[0])) & msk +} + +/* set x = x mod 2^m */ +func (r *BIG) mod2m(m uint) { + wd := int(m / BASEBITS) + bt := m % BASEBITS + msk := (Chunk(1) << bt) - 1 + r.w[wd] &= msk + for i := wd + 1; i < NLEN; i++ { + r.w[i] = 0 + } +} + +/* a=1/a mod 2^256. This is very fast! */ +func (r *BIG) invmod2m() { + U := NewBIG() + b := NewBIG() + c := NewBIG() + + U.inc(invmod256(r.lastbits(8))) + + for i := 8; i < BIGBITS; i <<= 1 { + U.norm() + ui := uint(i) + b.copy(r) + b.mod2m(ui) + t1 := smul(U, b) + t1.shr(ui) + c.copy(r) + c.shr(ui) + c.mod2m(ui) + + t2 := smul(U, c) + t2.mod2m(ui) + t1.add(t2) + t1.norm() + b = smul(t1, U) + t1.copy(b) + t1.mod2m(ui) + + t2.one() + t2.shl(ui) + t1.rsub(t2) + t1.norm() + t1.shl(ui) + U.add(t1) + } + U.mod2m(8 * MODBYTES) + r.copy(U) + r.norm() +} + +func (r *BIG) ctmod(m *BIG, bd uint) { + k := bd + sr := NewBIG() + c := NewBIGcopy(m) + r.norm() + + c.shl(k) + + for { + sr.copy(r) + sr.sub(c) + sr.norm() + r.cmove(sr, int(1-((sr.w[NLEN-1]>>uint(CHUNK-1))&1))) + if k == 0 { + break + } + c.fshr(1) + k -= 1 + } +} + +/* reduce this mod m */ +func (r *BIG) Mod(m *BIG) { + k := r.nbits() - m.nbits() + if k < 0 { + k = 0 + } + r.ctmod(m, uint(k)) +} + +func (r *BIG) ctdiv(m *BIG, bd uint) { + k := bd + e := NewBIGint(1) + sr := NewBIG() + a := NewBIGcopy(r) + c := NewBIGcopy(m) + r.norm() + r.zero() + + c.shl(k) + e.shl(k) + + for { + sr.copy(a) + sr.sub(c) + sr.norm() + d := int(1 - ((sr.w[NLEN-1] >> uint(CHUNK-1)) & 1)) + a.cmove(sr, d) + sr.copy(r) + sr.add(e) + sr.norm() + r.cmove(sr, d) + if k == 0 { + break + } + c.fshr(1) + e.fshr(1) + k -= 1 + } +} + +/* divide this by m */ +func (r *BIG) div(m *BIG) { + k := r.nbits() - m.nbits() + if k < 0 { + k = 0 + } + r.ctdiv(m, uint(k)) +} + +/* get 8*MODBYTES size random number */ +func Random(rng *core.RAND) *BIG { + m := NewBIG() + var j int = 0 + var r byte = 0 + /* generate random BIG */ + for i := 0; i < 8*int(MODBYTES); i++ { + if j == 0 { + r = rng.GetByte() + } else { + r >>= 1 + } + + b := Chunk(int(r & 1)) + m.shl(1) + m.w[0] += b + j++ + j &= 7 + } + return m +} + +/* Create random BIG in portable way, one bit at a time */ +func Randomnum(q *BIG, rng *core.RAND) *BIG { + d := NewDBIG() + var j int = 0 + var r byte = 0 + for i := 0; i < 2*q.nbits(); i++ { + if j == 0 { + r = rng.GetByte() + } else { + r >>= 1 + } + + b := Chunk(int(r & 1)) + d.shl(1) + d.w[0] += b + j++ + j &= 7 + } + m := d.Mod(q) + return m +} + +func Randtrunc(q *BIG, trunc int, rng *core.RAND) *BIG { + m := Randomnum(q, rng) + if q.nbits() > trunc { + m.mod2m(uint(trunc)) + } + return m +} + +/* return a*b mod m */ +func Modmul(a1, b1, m *BIG) *BIG { + a := NewBIGcopy(a1) + b := NewBIGcopy(b1) + a.Mod(m) + b.Mod(m) + d := mul(a, b) + return d.ctmod(m, uint(m.nbits())) +} + +/* return a^2 mod m */ +func Modsqr(a1, m *BIG) *BIG { + a := NewBIGcopy(a1) + a.Mod(m) + d := sqr(a) + return d.ctmod(m, uint(m.nbits())) +} + +/* return -a mod m */ +func Modneg(a1, m *BIG) *BIG { + a := NewBIGcopy(a1) + a.Mod(m) + a.rsub(m) + a.norm() + return a +} + +/* return a+b mod m */ +func Modadd(a1, b1, m *BIG) *BIG { + a := NewBIGcopy(a1) + b := NewBIGcopy(b1) + a.Mod(m) + b.Mod(m) + a.add(b) + a.norm() + a.ctmod(m, 1) + return a +} + +/* Jacobi Symbol (this/p). Returns 0, 1 or -1 */ +func (r *BIG) Jacobi(p *BIG) int { + m := 0 + t := NewBIGint(0) + x := NewBIGint(0) + n := NewBIGint(0) + zilch := NewBIGint(0) + one := NewBIGint(1) + if p.parity() == 0 || Comp(r, zilch) == 0 || Comp(p, one) <= 0 { + return 0 + } + r.norm() + x.copy(r) + n.copy(p) + x.Mod(p) + + for Comp(n, one) > 0 { + if Comp(x, zilch) == 0 { + return 0 + } + n8 := n.lastbits(3) + k := 0 + for x.parity() == 0 { + k++ + x.shr(1) + } + if k%2 == 1 { + m += (n8*n8 - 1) / 8 + } + m += (n8 - 1) * (x.lastbits(2) - 1) / 4 + t.copy(n) + t.Mod(x) + n.copy(x) + x.copy(t) + m %= 2 + + } + if m == 0 { + return 1 + } + return -1 +} + +/* this=1/this mod p. Binary method */ +func (r *BIG) Invmodp(p *BIG) { + r.Mod(p) + if r.iszilch() { + return + } + u := NewBIGcopy(r) + v := NewBIGcopy(p) + x1 := NewBIGint(1) + x2 := NewBIGint(0) + t := NewBIGint(0) + one := NewBIGint(1) + for Comp(u, one) != 0 && Comp(v, one) != 0 { + for u.parity() == 0 { + u.fshr(1) + t.copy(x1) + t.add(p) + x1.cmove(t, x1.parity()) + x1.norm() + x1.fshr(1) + } + for v.parity() == 0 { + v.fshr(1) + t.copy(x2) + t.add(p) + x2.cmove(t, x2.parity()) + x2.norm() + x2.fshr(1) + } + if Comp(u, v) >= 0 { + u.sub(v) + u.norm() + t.copy(x1) + t.add(p) + x1.cmove(t, (Comp(x1, x2)>>1)&1) + x1.sub(x2) + x1.norm() + } else { + v.sub(u) + v.norm() + t.copy(x2) + t.add(p) + x2.cmove(t, (Comp(x2, x1)>>1)&1) + x2.sub(x1) + x2.norm() + } + } + r.copy(x1) + r.cmove(x2, Comp(u, one)&1) +} + +/* return this^e mod m */ +func (r *BIG) Powmod(e1 *BIG, m *BIG) *BIG { + e := NewBIGcopy(e1) + r.norm() + e.norm() + a := NewBIGint(1) + z := NewBIGcopy(e) + s := NewBIGcopy(r) + for true { + bt := z.parity() + z.fshr(1) + if bt == 1 { + a = Modmul(a, s, m) + } + if z.iszilch() { + break + } + s = Modsqr(s, m) + } + return a +} + +/* Arazi and Qi inversion mod 256 */ +func invmod256(a int) int { + var t1 int = 0 + c := (a >> 1) & 1 + t1 += c + t1 &= 1 + t1 = 2 - t1 + t1 <<= 1 + U := t1 + 1 + + // i=2 + b := a & 3 + t1 = U * b + t1 >>= 2 + c = (a >> 2) & 3 + t2 := (U * c) & 3 + t1 += t2 + t1 *= U + t1 &= 3 + t1 = 4 - t1 + t1 <<= 2 + U += t1 + + // i=4 + b = a & 15 + t1 = U * b + t1 >>= 4 + c = (a >> 4) & 15 + t2 = (U * c) & 15 + t1 += t2 + t1 *= U + t1 &= 15 + t1 = 16 - t1 + t1 <<= 4 + U += t1 + + return U +} + +func logb2(w uint32) uint { + v := w + v |= (v >> 1) + v |= (v >> 2) + v |= (v >> 4) + v |= (v >> 8) + v |= (v >> 16) + + v = v - ((v >> 1) & 0x55555555) + v = (v & 0x33333333) + ((v >> 2) & 0x33333333) + r := uint((((v + (v >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24) + return (r) +} + +// Optimized combined shift, subtract and norm +func ssn(r *BIG, a *BIG, m *BIG) int { + n := NLEN - 1 + m.w[0] = (m.w[0] >> 1) | ((m.w[1] << (BASEBITS - 1)) & BMASK) + r.w[0] = a.w[0] - m.w[0] + carry := r.w[0] >> BASEBITS + r.w[0] &= BMASK + for i := 1; i < n; i++ { + m.w[i] = (m.w[i] >> 1) | ((m.w[i+1] << (BASEBITS - 1)) & BMASK) + r.w[i] = a.w[i] - m.w[i] + carry + carry = r.w[i] >> BASEBITS + r.w[i] &= BMASK + } + m.w[n] >>= 1 + r.w[n] = a.w[n] - m.w[n] + carry + return int((r.w[n] >> uint(CHUNK-1)) & 1) +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BLS.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BLS.go index 7ebb1f73f01..89b227e03ca 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BLS.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/BLS.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * @@ -27,8 +29,6 @@ package FP256BN import "github.com/hyperledger/fabric-amcl/core" - - const BFS int = int(MODBYTES) const BGS int = int(MODBYTES) const BLS_OK int = 0 @@ -36,35 +36,35 @@ const BLS_FAIL int = -1 var G2_TAB []*FP4 -func ceil(a int,b int) int { - return (((a)-1)/(b)+1) +func ceil(a int, b int) int { + return (((a)-1)/(b) + 1) } /* output u \in F_p */ -func hash_to_field(hash int,hlen int ,DST []byte,M []byte,ctr int) []*FP { +func hash_to_field(hash int, hlen int, DST []byte, M []byte, ctr int) []*FP { q := NewBIGints(Modulus) - L := ceil(q.nbits()+AESKEY*8,8) + nbq := q.nbits() + L := ceil(nbq+AESKEY*8, 8) var u []*FP - var fd =make([]byte,L) - OKM:=core.XMD_Expand(hash,hlen,L*ctr,DST,M) - - for i:=0;i>= 1; for i := 0; i < DNLEN; i++ { - r.w[i] ^= (r.w[i] ^ g.w[i]) & b + t :=(r.w[i] ^ g.w[i])&b + t^=v + e := r.w[i]^t; s^=e + r.w[i] = e^va } + return s } /* Compare a and b, return 0 if a==b, -1 if ab. Inputs must be normalised */ func dcomp(a *DBIG, b *DBIG) int { - gt:=Chunk(0) - eq:=Chunk(1) + gt := Chunk(0) + eq := Chunk(1) for i := DNLEN - 1; i >= 0; i-- { - gt |= ((b.w[i]-a.w[i]) >> BASEBITS) & eq - eq &= ((b.w[i]^a.w[i])-1) >> BASEBITS + gt |= ((b.w[i] - a.w[i]) >> BASEBITS) & eq + eq &= ((b.w[i] ^ a.w[i]) - 1) >> BASEBITS } - return int(gt+gt+eq-1) + return int(gt + gt + eq - 1) } /* Copy from another DBIG */ @@ -165,72 +171,70 @@ func (r *DBIG) shr(k uint) { } } -/* reduces this DBIG mod a BIG, and returns the BIG */ -func (r *DBIG) Mod(c *BIG) *BIG { +func (r *DBIG) ctmod(m *BIG,bd uint) *BIG { + k:=bd r.norm() - m := NewDBIGscopy(c) + c :=NewDBIGscopy(m) dr := NewDBIG() - if dcomp(r, m) < 0 { - return NewBIGdcopy(r) - } - - m.shl(1) - k := 1 - - for dcomp(r, m) >= 0 { - m.shl(1) - k++ - } - - for k > 0 { - m.shr(1) + c.shl(k) + for { dr.copy(r) - dr.sub(m) + dr.sub(c) dr.norm() r.cmove(dr, int(1-((dr.w[DNLEN-1]>>uint(CHUNK-1))&1))) - k-- + if k==0 {break} + k -= 1 + c.shr(1) } return NewBIGdcopy(r) } -/* return this/c */ -func (r *DBIG) div(c *BIG) *BIG { - var d int - k := 0 - m := NewDBIGscopy(c) +/* reduces this DBIG mod a BIG, and returns the BIG */ +func (r *DBIG) Mod(m *BIG) *BIG { + k:=r.nbits()-m.nbits() + if k<0 {k=0} + return r.ctmod(m,uint(k)) +} + +func (r *DBIG) ctdiv(m *BIG,bd uint) *BIG { + k:=bd + c := NewDBIGscopy(m) a := NewBIGint(0) e := NewBIGint(1) sr := NewBIG() dr := NewDBIG() r.norm() - for dcomp(r, m) >= 0 { - e.fshl(1) - m.shl(1) - k++ - } - - for k > 0 { - m.shr(1) - e.shr(1) + c.shl(k) + e.shl(k) + for { dr.copy(r) - dr.sub(m) + dr.sub(c) dr.norm() - d = int(1 - ((dr.w[DNLEN-1] >> uint(CHUNK-1)) & 1)) + d := int(1 - ((dr.w[DNLEN-1] >> uint(CHUNK-1)) & 1)) r.cmove(dr, d) sr.copy(a) sr.add(e) sr.norm() - a.cmove(sr, d) - - k-- + a.cmove(sr, d) + if k==0 {break} + k -= 1 + c.shr(1) + e.shr(1) } return a } +/* return this/c */ +func (r *DBIG) div(m *BIG) *BIG { + k:=r.nbits()-m.nbits() + if k<0 {k=0} + return r.ctdiv(m,uint(k)) +} + /* Convert to Hex String */ func (r *DBIG) toString() string { s := "" diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH.go index 5e9b2410aa2..7cbe00b0ce9 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * @@ -21,15 +23,32 @@ package FP256BN - import "github.com/hyperledger/fabric-amcl/core" -const INVALID_PUBLIC_KEY int = -2 -const ERROR int = -3 -//const INVALID int = -4 +const ECDH_INVALID_PUBLIC_KEY int = -2 +const ECDH_ERROR int = -3 + +// const INVALID int = -4 const EFS int = int(MODBYTES) const EGS int = int(MODBYTES) +// Transform a point multiplier to RFC7748 form +func RFC7748(r *BIG) { + lg := 0 + t := NewBIGint(1) + c := CURVE_Cof_I + for c != 1 { + lg++ + c /= 2 + } + n := uint(8*EGS - lg + 1) + r.mod2m(n) + t.shl(n) + r.add(t) + c = r.lastbits(lg) + r.dec(c) +} + /* return true if S is in ranger 0 < S < order , else return false */ func ECDH_IN_RANGE(S []byte) bool { r := NewBIGints(CURVE_Order) @@ -37,7 +56,7 @@ func ECDH_IN_RANGE(S []byte) bool { if s.iszilch() { return false } - if Comp(s,r)>=0 { + if Comp(s, r) >= 0 { return false } return true @@ -54,20 +73,24 @@ func ECDH_KEY_PAIR_GENERATE(RNG *core.RAND, S []byte, W []byte) int { var G *ECP G = ECP_generator() - r := NewBIGints(CURVE_Order) if RNG == nil { s = FromBytes(S) - s.Mod(r) } else { - s = Randtrunc(r, 16*AESKEY, RNG) + if CURVETYPE != WEIERSTRASS { + s = Random(RNG) // from random bytes + } else { + s = Randomnum(r, RNG) // Removes biases + } } - s.ToBytes(S) - - WP := G.mul(s) + if CURVETYPE != WEIERSTRASS { + RFC7748(s) // For Montgomery or Edwards, apply RFC7748 transformation + } + s.ToBytes(S) + WP := G.clmul(s, r) WP.ToBytes(W, false) // To use point compression on public keys, change to true return res @@ -81,7 +104,7 @@ func ECDH_PUBLIC_KEY_VALIDATE(W []byte) int { r := NewBIGints(CURVE_Order) if WP.Is_infinity() { - res = INVALID_PUBLIC_KEY + res = ECDH_INVALID_PUBLIC_KEY } if res == 0 { @@ -101,7 +124,7 @@ func ECDH_PUBLIC_KEY_VALIDATE(W []byte) int { WP = WP.mul(k) } if WP.Is_infinity() { - res = INVALID_PUBLIC_KEY + res = ECDH_INVALID_PUBLIC_KEY } } @@ -112,34 +135,33 @@ func ECDH_PUBLIC_KEY_VALIDATE(W []byte) int { // type = 0 is just x coordinate output // type = 1 for standard compressed output // type = 2 for standard uncompress output 04|x|y -func ECDH_ECPSVDP_DH(S []byte, WD []byte, Z []byte,typ int) int { +func ECDH_ECPSVDP_DH(S []byte, WD []byte, Z []byte, typ int) int { res := 0 s := FromBytes(S) W := ECP_fromBytes(WD) if W.Is_infinity() { - res = ERROR + res = ECDH_ERROR } if res == 0 { r := NewBIGints(CURVE_Order) - s.Mod(r) - W = W.mul(s) + W = W.clmul(s, r) if W.Is_infinity() { - res = ERROR + res = ECDH_ERROR } else { if CURVETYPE != MONTGOMERY { - if typ>0 { - if typ==1 { - W.ToBytes(Z,true) + if typ > 0 { + if typ == 1 { + W.ToBytes(Z, true) } else { - W.ToBytes(Z,false) + W.ToBytes(Z, false) } } else { W.GetX().ToBytes(Z) } - return res; + return res } else { W.GetX().ToBytes(Z) } @@ -150,13 +172,12 @@ func ECDH_ECPSVDP_DH(S []byte, WD []byte, Z []byte,typ int) int { /* IEEE ECDSA Signature, C and D are signature on F using private key S */ func ECDH_ECPSP_DSA(sha int, RNG *core.RAND, S []byte, F []byte, C []byte, D []byte) int { - var T [EFS]byte + var T [EGS]byte - B := core.GPhashit(core.MC_SHA2, sha, int(MODBYTES), 0, F, -1, nil ) + B := core.GPhashit(core.MC_SHA2, sha, EGS, 0, F, -1, nil) G := ECP_generator() r := NewBIGints(CURVE_Order) - s := FromBytes(S) f := FromBytes(B[:]) @@ -166,9 +187,10 @@ func ECDH_ECPSP_DSA(sha int, RNG *core.RAND, S []byte, F []byte, C []byte, D []b for d.iszilch() { u := Randomnum(r, RNG) - w := Randomnum(r, RNG) /* side channel masking */ + w := Randomnum(r, RNG) /* IMPORTANT - side channel masking to protect invmodp() */ + V.Copy(G) - V = V.mul(u) + V = V.clmul(u, r) vx := V.GetX() c.copy(vx) c.Mod(r) @@ -178,17 +200,17 @@ func ECDH_ECPSP_DSA(sha int, RNG *core.RAND, S []byte, F []byte, C []byte, D []b u.copy(Modmul(u, w, r)) u.Invmodp(r) d.copy(Modmul(s, c, r)) - d.add(f) + d.copy(Modadd(d, f, r)) d.copy(Modmul(d, w, r)) d.copy(Modmul(u, d, r)) } c.ToBytes(T[:]) - for i := 0; i < EFS; i++ { + for i := 0; i < EGS; i++ { C[i] = T[i] } d.ToBytes(T[:]) - for i := 0; i < EFS; i++ { + for i := 0; i < EGS; i++ { D[i] = T[i] } return 0 @@ -198,7 +220,7 @@ func ECDH_ECPSP_DSA(sha int, RNG *core.RAND, S []byte, F []byte, C []byte, D []b func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { res := 0 - B := core.GPhashit(core.MC_SHA2, sha, int(MODBYTES), 0, F, -1, nil ) + B := core.GPhashit(core.MC_SHA2, sha, EGS, 0, F, -1, nil) G := ECP_generator() r := NewBIGints(CURVE_Order) @@ -208,7 +230,7 @@ func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { f := FromBytes(B[:]) if c.iszilch() || Comp(c, r) >= 0 || d.iszilch() || Comp(d, r) >= 0 { - res = ERROR + res = ECDH_ERROR } if res == 0 { @@ -218,7 +240,7 @@ func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { WP := ECP_fromBytes(W) if WP.Is_infinity() { - res = ERROR + res = ECDH_ERROR } else { P := NewECP() P.Copy(WP) @@ -226,13 +248,13 @@ func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { P = P.Mul2(h2, G, f) if P.Is_infinity() { - res = ERROR + res = ECDH_ERROR } else { d = P.GetX() d.Mod(r) if Comp(d, c) != 0 { - res = ERROR + res = ECDH_ERROR } } } @@ -350,7 +372,7 @@ func ECDH_ECIES_DECRYPT(sha int, P1 []byte, P2 []byte, V []byte, C []byte, T []b AC = append(AC, L2[i]) } - core.HMAC(core.MC_SHA2, sha, TAG, len(TAG), K2[:],AC) + core.HMAC(core.MC_SHA2, sha, TAG, len(TAG), K2[:], AC) if !ncomp(T, TAG, len(T)) { return nil diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH_32.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH_32.go new file mode 100644 index 00000000000..26c7b4e6ce2 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECDH_32.go @@ -0,0 +1,382 @@ +//go:build 386 || arm + +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* ECDH/ECIES/ECDSA API Functions */ + +package FP256BN + +import "github.com/hyperledger/fabric-amcl/core" + +const ECDH_INVALID_PUBLIC_KEY int = -2 +const ECDH_ERROR int = -3 + +// const INVALID int = -4 +const EFS int = int(MODBYTES) +const EGS int = int(MODBYTES) + +// Transform a point multiplier to RFC7748 form +func RFC7748(r *BIG) { + lg := 0 + t := NewBIGint(1) + c := CURVE_Cof_I + for c != 1 { + lg++ + c /= 2 + } + n := uint(8*EGS - lg + 1) + r.mod2m(n) + t.shl(n) + r.add(t) + c = r.lastbits(lg) + r.dec(c) +} + +/* return true if S is in ranger 0 < S < order , else return false */ +func ECDH_IN_RANGE(S []byte) bool { + r := NewBIGints(CURVE_Order) + s := FromBytes(S) + if s.iszilch() { + return false + } + if Comp(s, r) >= 0 { + return false + } + return true +} + +/* Calculate a public/private EC GF(p) key pair W,S where W=S.G mod EC(p), + * where S is the secret key and W is the public key + * and G is fixed generator. + * If RNG is NULL then the private key is provided externally in S + * otherwise it is generated randomly internally */ +func ECDH_KEY_PAIR_GENERATE(RNG *core.RAND, S []byte, W []byte) int { + res := 0 + var s *BIG + var G *ECP + + G = ECP_generator() + r := NewBIGints(CURVE_Order) + + if RNG == nil { + s = FromBytes(S) + } else { + if CURVETYPE != WEIERSTRASS { + s = Random(RNG) // from random bytes + } else { + s = Randomnum(r, RNG) // Removes biases + } + } + + if CURVETYPE != WEIERSTRASS { + RFC7748(s) // For Montgomery or Edwards, apply RFC7748 transformation + } + + s.ToBytes(S) + WP := G.clmul(s, r) + WP.ToBytes(W, false) // To use point compression on public keys, change to true + + return res +} + +/* validate public key */ +func ECDH_PUBLIC_KEY_VALIDATE(W []byte) int { + WP := ECP_fromBytes(W) + res := 0 + + r := NewBIGints(CURVE_Order) + + if WP.Is_infinity() { + res = ECDH_INVALID_PUBLIC_KEY + } + if res == 0 { + + q := NewBIGints(Modulus) + nb := q.nbits() + k := NewBIGint(1) + k.shl(uint((nb + 4) / 2)) + k.add(q) + k.div(r) + + for k.parity() == 0 { + k.shr(1) + WP.dbl() + } + + if !k.isunity() { + WP = WP.mul(k) + } + if WP.Is_infinity() { + res = ECDH_INVALID_PUBLIC_KEY + } + + } + return res +} + +/* IEEE-1363 Diffie-Hellman online calculation Z=S.WD */ +// type = 0 is just x coordinate output +// type = 1 for standard compressed output +// type = 2 for standard uncompress output 04|x|y +func ECDH_ECPSVDP_DH(S []byte, WD []byte, Z []byte, typ int) int { + res := 0 + + s := FromBytes(S) + + W := ECP_fromBytes(WD) + if W.Is_infinity() { + res = ECDH_ERROR + } + + if res == 0 { + r := NewBIGints(CURVE_Order) + W = W.clmul(s, r) + if W.Is_infinity() { + res = ECDH_ERROR + } else { + if CURVETYPE != MONTGOMERY { + if typ > 0 { + if typ == 1 { + W.ToBytes(Z, true) + } else { + W.ToBytes(Z, false) + } + } else { + W.GetX().ToBytes(Z) + } + return res + } else { + W.GetX().ToBytes(Z) + } + } + } + return res +} + +/* IEEE ECDSA Signature, C and D are signature on F using private key S */ +func ECDH_ECPSP_DSA(sha int, RNG *core.RAND, S []byte, F []byte, C []byte, D []byte) int { + var T [EGS]byte + + B := core.GPhashit(core.MC_SHA2, sha, EGS, 0, F, -1, nil) + G := ECP_generator() + + r := NewBIGints(CURVE_Order) + s := FromBytes(S) + f := FromBytes(B[:]) + + c := NewBIGint(0) + d := NewBIGint(0) + V := NewECP() + + for d.iszilch() { + u := Randomnum(r, RNG) + w := Randomnum(r, RNG) /* IMPORTANT - side channel masking to protect invmodp() */ + + V.Copy(G) + V = V.clmul(u, r) + vx := V.GetX() + c.copy(vx) + c.Mod(r) + if c.iszilch() { + continue + } + u.copy(Modmul(u, w, r)) + u.Invmodp(r) + d.copy(Modmul(s, c, r)) + d.copy(Modadd(d, f, r)) + d.copy(Modmul(d, w, r)) + d.copy(Modmul(u, d, r)) + } + + c.ToBytes(T[:]) + for i := 0; i < EGS; i++ { + C[i] = T[i] + } + d.ToBytes(T[:]) + for i := 0; i < EGS; i++ { + D[i] = T[i] + } + return 0 +} + +/* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */ +func ECDH_ECPVP_DSA(sha int, W []byte, F []byte, C []byte, D []byte) int { + res := 0 + + B := core.GPhashit(core.MC_SHA2, sha, EGS, 0, F, -1, nil) + + G := ECP_generator() + r := NewBIGints(CURVE_Order) + + c := FromBytes(C) + d := FromBytes(D) + f := FromBytes(B[:]) + + if c.iszilch() || Comp(c, r) >= 0 || d.iszilch() || Comp(d, r) >= 0 { + res = ECDH_ERROR + } + + if res == 0 { + d.Invmodp(r) + f.copy(Modmul(f, d, r)) + h2 := Modmul(c, d, r) + + WP := ECP_fromBytes(W) + if WP.Is_infinity() { + res = ECDH_ERROR + } else { + P := NewECP() + P.Copy(WP) + + P = P.Mul2(h2, G, f) + + if P.Is_infinity() { + res = ECDH_ERROR + } else { + d = P.GetX() + d.Mod(r) + + if Comp(d, c) != 0 { + res = ECDH_ERROR + } + } + } + } + + return res +} + +/* IEEE1363 ECIES encryption. Encryption of plaintext M uses public key W and produces ciphertext V,C,T */ +func ECDH_ECIES_ENCRYPT(sha int, P1 []byte, P2 []byte, RNG *core.RAND, W []byte, M []byte, V []byte, T []byte) []byte { + var Z [EFS]byte + var VZ [3*EFS + 1]byte + var K1 [AESKEY]byte + var K2 [AESKEY]byte + var U [EGS]byte + + if ECDH_KEY_PAIR_GENERATE(RNG, U[:], V) != 0 { + return nil + } + if ECDH_ECPSVDP_DH(U[:], W, Z[:], 0) != 0 { + return nil + } + + for i := 0; i < 2*EFS+1; i++ { + VZ[i] = V[i] + } + for i := 0; i < EFS; i++ { + VZ[2*EFS+1+i] = Z[i] + } + + K := core.KDF2(core.MC_SHA2, sha, VZ[:], P1, 2*AESKEY) + + for i := 0; i < AESKEY; i++ { + K1[i] = K[i] + K2[i] = K[AESKEY+i] + } + + C := core.AES_CBC_IV0_ENCRYPT(K1[:], M) + + L2 := core.InttoBytes(len(P2), 8) + + var AC []byte + + for i := 0; i < len(C); i++ { + AC = append(AC, C[i]) + } + for i := 0; i < len(P2); i++ { + AC = append(AC, P2[i]) + } + for i := 0; i < 8; i++ { + AC = append(AC, L2[i]) + } + + core.HMAC(core.MC_SHA2, sha, T, len(T), K2[:], AC) + + return C +} + +/* constant time n-byte compare */ +func ncomp(T1 []byte, T2 []byte, n int) bool { + res := 0 + for i := 0; i < n; i++ { + res |= int(T1[i] ^ T2[i]) + } + if res == 0 { + return true + } + return false +} + +/* IEEE1363 ECIES decryption. Decryption of ciphertext V,C,T using private key U outputs plaintext M */ +func ECDH_ECIES_DECRYPT(sha int, P1 []byte, P2 []byte, V []byte, C []byte, T []byte, U []byte) []byte { + var Z [EFS]byte + var VZ [3*EFS + 1]byte + var K1 [AESKEY]byte + var K2 [AESKEY]byte + + var TAG []byte = T[:] + + if ECDH_ECPSVDP_DH(U, V, Z[:], 0) != 0 { + return nil + } + + for i := 0; i < 2*EFS+1; i++ { + VZ[i] = V[i] + } + for i := 0; i < EFS; i++ { + VZ[2*EFS+1+i] = Z[i] + } + + K := core.KDF2(core.MC_SHA2, sha, VZ[:], P1, 2*AESKEY) + + for i := 0; i < AESKEY; i++ { + K1[i] = K[i] + K2[i] = K[AESKEY+i] + } + + M := core.AES_CBC_IV0_DECRYPT(K1[:], C) + + if M == nil { + return nil + } + + L2 := core.InttoBytes(len(P2), 8) + + var AC []byte + + for i := 0; i < len(C); i++ { + AC = append(AC, C[i]) + } + for i := 0; i < len(P2); i++ { + AC = append(AC, P2[i]) + } + for i := 0; i < 8; i++ { + AC = append(AC, L2[i]) + } + + core.HMAC(core.MC_SHA2, sha, TAG, len(TAG), K2[:], AC) + + if !ncomp(T, TAG, len(T)) { + return nil + } + + return M +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECP.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECP.go index 840b9e703b3..e361bb364a3 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECP.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/ECP.go @@ -19,6 +19,7 @@ package FP256BN + /* Elliptic Curve Point Structure */ type ECP struct { @@ -337,7 +338,7 @@ func (E *ECP) getz() *FP { func (E *ECP) ToBytes(b []byte, compress bool) { var t [int(MODBYTES)]byte MB := int(MODBYTES) - alt:=false + alt := false W := NewECP() W.Copy(E) W.Affine() @@ -352,24 +353,24 @@ func (E *ECP) ToBytes(b []byte, compress bool) { } if (MODBITS-1)%8 <= 4 && ALLOW_ALT_COMPRESS { - alt=true + alt = true } if alt { - for i:=0;i>5 - P:=NewECPbigint(px,0) - cmp:=P.y.islarger() - if (sgn==1 && cmp!=1) || (sgn==0 && cmp==1) { + py := FromBytes(t[:]) + return NewECPbigs(px, py) + } else { + sgn := (b[0] & 0x20) >> 5 + P := NewECPbigint(px, 0) + cmp := P.y.islarger() + if (sgn == 1 && cmp != 1) || (sgn == 0 && cmp == 1) { P.Neg() } - return P - } + return P + } } else { for i := 0; i < MB; i++ { t[i] = b[i+1] @@ -1005,13 +1006,32 @@ func (E *ECP) pinmul(e int32, bts int32) *ECP { } } -/* return e.this */ +// Point multiplication, multiplies a point P by a scalar e +// This code has no inherent awareness of the order of the curve, or the order of the point. +// The order of the curve will be h.r, where h is a cofactor, and r is a large prime +// Typically P will be of order r (but not always), and typically e will be less than r (but not always) +// A problem can arise if a secret e is a few bits less than r, as the leading zeros in e will leak via a timing attack +// The secret e may however be greater than r (see RFC7748 which combines elimination of a small cofactor h with the point multiplication, using an e>r) +// Our solution is to use as a multiplier an e, whose length in bits is that of the logical OR of e and r, hence allowing e>r while forcing inclusion of leading zeros if e= 0; i-- { b := int(e.bit(i)) P.Copy(R1) @@ -1067,7 +1088,7 @@ func (E *ECP) mul(e *BIG) *ECP { Q.cmove(E, ns) C.Copy(Q) - nb := 1 + (t.nbits()+3)/4 + nb := 1 + (max+3)/4 // convert exponent to signed 4-bit window for i := 0; i < nb; i++ { @@ -1078,7 +1099,8 @@ func (E *ECP) mul(e *BIG) *ECP { } w[nb] = int8(t.lastbits(5)) - P.Copy(W[(int(w[nb])-1)/2]) + //P.Copy(W[(int(w[nb])-1)/2]) + P.selector(W, int32(w[nb])) for i := nb - 1; i >= 0; i-- { Q.selector(W, int32(w[i])) P.dbl() @@ -1098,43 +1120,47 @@ func (E *ECP) Mul(e *BIG) *ECP { } // Generic multi-multiplication, fixed 4-bit window, P=Sigma e_i*X_i -func ECP_muln(n int, X []*ECP, e []*BIG ) *ECP { - P:=NewECP() - R:=NewECP() - S:=NewECP() +func ECP_muln(n int, X []*ECP, e []*BIG) *ECP { + P := NewECP() + R := NewECP() + S := NewECP() var B []*ECP t := NewBIG() - for i:=0;i<16;i++ { - B = append(B,NewECP()) - } - mt:=NewBIGcopy(e[0]); mt.norm(); - for i:=1;i=0;i-- { - for j:=0;j<16;j++ { - B[j].inf() - } - for j:=0;j=1;j-- { - R.Add(B[j]) - S.Add(R) - } - for j:=0;j<4;j++ { - P.dbl() - } - P.Add(S) - } - return P + for i := 0; i < 16; i++ { + B = append(B, NewECP()) + } + mt := NewBIGcopy(e[0]) + mt.norm() + for i := 1; i < n; i++ { // find biggest + t.copy(e[i]) + t.norm() + k := Comp(t, mt) + mt.cmove(t, (k+1)/2) + } + nb := (mt.nbits() + 3) / 4 + for i := nb - 1; i >= 0; i-- { + for j := 0; j < 16; j++ { + B[j].inf() + } + for j := 0; j < n; j++ { + mt.copy(e[j]) + mt.norm() + mt.shr(uint(i * 4)) + k := mt.lastbits(4) + B[k].Add(X[j]) + } + R.inf() + S.inf() + for j := 15; j >= 1; j-- { + R.Add(B[j]) + S.Add(R) + } + for j := 0; j < 4; j++ { + P.dbl() + } + P.Add(S) + } + return P } /* Return e.this+f.Q */ @@ -1219,8 +1245,8 @@ func (E *ECP) Mul2(e *BIG, Q *ECP, f *BIG) *ECP { w[i] = int8(4*a + b) } w[nb] = int8(4*te.lastbits(3) + tf.lastbits(3)) - S.Copy(W[(w[nb]-1)/2]) - + //S.Copy(W[(w[nb]-1)/2]) + S.selector(W, int32(w[nb])) for i := nb - 1; i >= 0; i-- { T.selector(W, int32(w[i])) S.dbl() @@ -1256,7 +1282,6 @@ func ECP_hap2point(h *BIG) *ECP { var P *ECP x := NewBIGcopy(h) - for true { if CURVETYPE != MONTGOMERY { P = NewECPbigint(x, 0) @@ -1277,436 +1302,518 @@ func ECP_map2point(h *FP) *ECP { P := NewECP() if CURVETYPE == MONTGOMERY { -// Elligator 2 - X1:=NewFP() - X2:=NewFP() - w:=NewFP() - one:=NewFPint(1) - A:=NewFPint(CURVE_A) - t:=NewFPcopy(h) - N:=NewFP() - D:=NewFP() - hint:=NewFP() - - t.sqr(); - - if PM1D2 == 2 { - t.add(t) - } - if PM1D2 == 1 { - t.neg(); - } - if PM1D2 > 2 { - t.imul(QNRI); - } - - t.norm() - D.copy(t); D.add(one); D.norm() - - X1.copy(A) - X1.neg(); X1.norm() - X2.copy(X1) - X2.mul(t) - - w.copy(X1); w.sqr(); N.copy(w); N.mul(X1) - w.mul(A); w.mul(D); N.add(w) - t.copy(D); t.sqr() - t.mul(X1) - N.add(t); N.norm() - - t.copy(N); t.mul(D) - qres:=t.qr(hint) - w.copy(t); w.inverse(hint) - D.copy(w); D.mul(N) - X1.mul(D) - X2.mul(D) - X1.cmove(X2,1-qres) - - a:=X1.redc() - P.Copy(NewECPbig(a)) + // Elligator 2 + X1 := NewFP() + X2 := NewFP() + w := NewFP() + one := NewFPint(1) + A := NewFPint(CURVE_A) + t := NewFPcopy(h) + N := NewFP() + D := NewFP() + hint := NewFP() + + t.sqr() + + if PM1D2 == 2 { + t.add(t) + } + if PM1D2 == 1 { + t.neg() + } + if PM1D2 > 2 { + t.imul(QNRI) + } + + t.norm() + D.copy(t) + D.add(one) + D.norm() + + X1.copy(A) + X1.neg() + X1.norm() + X2.copy(X1) + X2.mul(t) + + w.copy(X1) + w.sqr() + N.copy(w) + N.mul(X1) + w.mul(A) + w.mul(D) + N.add(w) + t.copy(D) + t.sqr() + t.mul(X1) + N.add(t) + N.norm() + + t.copy(N) + t.mul(D) + qres := t.qr(hint) + w.copy(t) + w.inverse(hint) + D.copy(w) + D.mul(N) + X1.mul(D) + X2.mul(D) + X1.cmove(X2, 1-qres) + + a := X1.redc() + P.Copy(NewECPbig(a)) } if CURVETYPE == EDWARDS { -// Elligator 2 - map to Montgomery, place point, map back - X1:=NewFP() - X2:=NewFP() - t:=NewFPcopy(h) - w:=NewFP() - one:=NewFPint(1) - A:=NewFP() - w1:=NewFP() - w2:=NewFP() - B:=NewFPbig(NewBIGints(CURVE_B)) - Y:=NewFP() - K:=NewFP() - D:=NewFP() - hint:=NewFP() - //Y3:=NewFP() - rfc:=0 - - if MODTYPE != GENERALISED_MERSENNE { - A.copy(B) - - if (CURVE_A==1) { - A.add(one) - B.sub(one) - } else { - A.sub(one) - B.add(one) - } - A.norm(); B.norm() - - A.div2() - B.div2() - B.div2() - - K.copy(B) - K.neg(); K.norm() - //K.inverse(nil) - K.invsqrt(K,w1); - - rfc=RIADZ - if rfc==1 { // RFC7748 - A.mul(K) - K.mul(w1); - //K=K.sqrt(nil) - } else { - B.sqr() - } + // Elligator 2 - map to Montgomery, place point, map back + X1 := NewFP() + X2 := NewFP() + t := NewFPcopy(h) + w := NewFP() + one := NewFPint(1) + A := NewFP() + w1 := NewFP() + w2 := NewFP() + B := NewFPbig(NewBIGints(CURVE_B)) + Y := NewFP() + K := NewFP() + D := NewFP() + hint := NewFP() + //Y3:=NewFP() + rfc := 0 + + if MODTYPE != GENERALISED_MERSENNE { + A.copy(B) + + if CURVE_A == 1 { + A.add(one) + B.sub(one) } else { - rfc=1 - A.copy(NewFPint(156326)) + A.sub(one) + B.add(one) } + A.norm() + B.norm() + + A.div2() + B.div2() + B.div2() + + K.copy(B) + K.neg() + K.norm() + //K.inverse(nil) + K.invsqrt(K, w1) + + rfc = RIADZ + if rfc == 1 { // RFC7748 + A.mul(K) + K.mul(w1) + //K=K.sqrt(nil) + } else { + B.sqr() + } + } else { + rfc = 1 + A.copy(NewFPint(156326)) + } - t.sqr() - qnr:=0 - if PM1D2 == 2 { - t.add(t) - qnr=2 - } - if PM1D2 == 1 { - t.neg(); - qnr=-1 - } - if PM1D2 > 2 { - t.imul(QNRI); - qnr=QNRI - } - t.norm() + t.sqr() + qnr := 0 + if PM1D2 == 2 { + t.add(t) + qnr = 2 + } + if PM1D2 == 1 { + t.neg() + qnr = -1 + } + if PM1D2 > 2 { + t.imul(QNRI) + qnr = QNRI + } + t.norm() - D.copy(t); D.add(one); D.norm() - X1.copy(A) - X1.neg(); X1.norm() - X2.copy(X1); X2.mul(t) - -// Figure out RHS of Montgomery curve in rational form gx1/d^3 - - w.copy(X1); w.sqr(); w1.copy(w); w1.mul(X1) - w.mul(A); w.mul(D); w1.add(w) - w2.copy(D); w2.sqr() - - if rfc==0 { - w.copy(X1); w.mul(B) - w2.mul(w) - w1.add(w2) - } else { - w2.mul(X1) - w1.add(w2) - } - w1.norm() - - B.copy(w1); B.mul(D) - qres:=B.qr(hint) - w.copy(B); w.inverse(hint) - D.copy(w); D.mul(w1) - X1.mul(D) - X2.mul(D) - D.sqr() - - w1.copy(B); w1.imul(qnr) - w.copy(NewFPbig(NewBIGints(CURVE_HTPC))) - w.mul(hint) - w2.copy(D); w2.mul(h) - - X1.cmove(X2,1-qres) - B.cmove(w1,1-qres) - hint.cmove(w,1-qres) - D.cmove(w2,1-qres) - - Y.copy(B.sqrt(hint)) - Y.mul(D) + D.copy(t) + D.add(one) + D.norm() + X1.copy(A) + X1.neg() + X1.norm() + X2.copy(X1) + X2.mul(t) + + // Figure out RHS of Montgomery curve in rational form gx1/d^3 + + w.copy(X1) + w.sqr() + w1.copy(w) + w1.mul(X1) + w.mul(A) + w.mul(D) + w1.add(w) + w2.copy(D) + w2.sqr() + + if rfc == 0 { + w.copy(X1) + w.mul(B) + w2.mul(w) + w1.add(w2) + } else { + w2.mul(X1) + w1.add(w2) + } + w1.norm() -/* - Y.copy(B.sqrt(hint)) - Y.mul(D) - - B.imul(qnr) - w.copy(NewFPbig(NewBIGints(CURVE_HTPC))) - hint.mul(w) - - Y3.copy(B.sqrt(hint)) - D.mul(h) - Y3.mul(D) - - X1.cmove(X2,1-qres) - Y.cmove(Y3,1-qres) -*/ - w.copy(Y); w.neg(); w.norm() - Y.cmove(w,qres^Y.sign()) - - if rfc==0 { - X1.mul(K) - Y.mul(K) - } - - if MODTYPE == GENERALISED_MERSENNE { - t.copy(X1); t.sqr() - w.copy(t); w.add(one); w.norm() - t.sub(one); t.norm() - w1.copy(t); w1.mul(Y) - w1.add(w1); X2.copy(w1); X2.add(w1); X2.norm() - t.sqr() - Y.sqr(); Y.add(Y); Y.add(Y); Y.norm() - B.copy(t); B.add(Y); B.norm() - - w2.copy(Y); w2.sub(t); w2.norm() - w2.mul(X1) - t.mul(X1) - Y.div2() - w1.copy(Y); w1.mul(w) - w1.rsub(t); w1.norm() - - t.copy(X2); t.mul(w1) - P.x.copy(t) - t.copy(w2); t.mul(B) - P.y.copy(t) - t.copy(w1); t.mul(B) - P.z.copy(t) - - return P; - } else { - w1.copy(X1); w1.add(one); w1.norm() - w2.copy(X1); w2.sub(one); w2.norm() - t.copy(w1); t.mul(Y) - X1.mul(w1) - - if rfc==1 { - X1.mul(K) - } - Y.mul(w2) - P.x.copy(X1) - P.y.copy(Y) - P.z.copy(t) - - return P + B.copy(w1) + B.mul(D) + qres := B.qr(hint) + w.copy(B) + w.inverse(hint) + D.copy(w) + D.mul(w1) + X1.mul(D) + X2.mul(D) + D.sqr() + + w1.copy(B) + w1.imul(qnr) + w.copy(NewFPbig(NewBIGints(CURVE_HTPC))) + w.mul(hint) + w2.copy(D) + w2.mul(h) + + X1.cmove(X2, 1-qres) + B.cmove(w1, 1-qres) + hint.cmove(w, 1-qres) + D.cmove(w2, 1-qres) + + Y.copy(B.sqrt(hint)) + Y.mul(D) + + /* + Y.copy(B.sqrt(hint)) + Y.mul(D) + + B.imul(qnr) + w.copy(NewFPbig(NewBIGints(CURVE_HTPC))) + hint.mul(w) + + Y3.copy(B.sqrt(hint)) + D.mul(h) + Y3.mul(D) + + X1.cmove(X2,1-qres) + Y.cmove(Y3,1-qres) + */ + w.copy(Y) + w.neg() + w.norm() + Y.cmove(w, qres^Y.sign()) + + if rfc == 0 { + X1.mul(K) + Y.mul(K) + } + + if MODTYPE == GENERALISED_MERSENNE { + t.copy(X1) + t.sqr() + w.copy(t) + w.add(one) + w.norm() + t.sub(one) + t.norm() + w1.copy(t) + w1.mul(Y) + w1.add(w1) + X2.copy(w1) + X2.add(w1) + X2.norm() + t.sqr() + Y.sqr() + Y.add(Y) + Y.add(Y) + Y.norm() + B.copy(t) + B.add(Y) + B.norm() + + w2.copy(Y) + w2.sub(t) + w2.norm() + w2.mul(X1) + t.mul(X1) + Y.div2() + w1.copy(Y) + w1.mul(w) + w1.rsub(t) + w1.norm() + + t.copy(X2) + t.mul(w1) + P.x.copy(t) + t.copy(w2) + t.mul(B) + P.y.copy(t) + t.copy(w1) + t.mul(B) + P.z.copy(t) + + return P + } else { + w1.copy(X1) + w1.add(one) + w1.norm() + w2.copy(X1) + w2.sub(one) + w2.norm() + t.copy(w1) + t.mul(Y) + X1.mul(w1) + + if rfc == 1 { + X1.mul(K) } + Y.mul(w2) + P.x.copy(X1) + P.y.copy(Y) + P.z.copy(t) + + return P + } } if CURVETYPE == WEIERSTRASS { - // swu method - A:=NewFP() - B:=NewFP() - X1:=NewFP() - X2:=NewFP() - X3:=NewFP() - one:=NewFPint(1) - Y:=NewFP() - D:=NewFP() - t:=NewFPcopy(h) - w:=NewFP() - D2:=NewFP() - hint:=NewFP() - GX1:=NewFP() - //Y3:=NewFP() - sgn:=t.sign() - - if CURVE_A != 0 || HTC_ISO != 0{ - if HTC_ISO!=0 { -/* CAHCZS - A.copy(NewFPbig(NewBIGints(CURVE_Ad))) - B.copy(NewFPbig(NewBIGints(CURVE_Bd))) -CAHCZF */ - } else { - A.copy(NewFPint(CURVE_A)) - B.copy(NewFPbig(NewBIGints(CURVE_B))) - } - // SSWU method - t.sqr(); - t.imul(RIADZ) - w.copy(t); w.add(one); w.norm() - - w.mul(t); D.copy(A) - D.mul(w) - - w.add(one); w.norm() - w.mul(B) - w.neg(); w.norm() - - X2.copy(w); - X3.copy(t); X3.mul(X2) - -// x^3+Ad^2x+Bd^3 - GX1.copy(X2); GX1.sqr(); D2.copy(D) - D2.sqr(); w.copy(A); w.mul(D2); GX1.add(w); GX1.norm(); GX1.mul(X2); D2.mul(D);w.copy(B); w.mul(D2); GX1.add(w); GX1.norm() - - w.copy(GX1); w.mul(D) - qr:=w.qr(hint) - D.copy(w); D.inverse(hint) - D.mul(GX1) - X2.mul(D) - X3.mul(D) - t.mul(h) - D2.copy(D); D2.sqr() - - - D.copy(D2); D.mul(t) - t.copy(w); t.imul(RIADZ) - X1.copy(NewFPbig(NewBIGints(CURVE_HTPC))) - X1.mul(hint) - - X2.cmove(X3,1-qr) - D2.cmove(D,1-qr) - w.cmove(t,1-qr) - hint.cmove(X1,1-qr) - - Y.copy(w.sqrt(hint)) - Y.mul(D2) -/* - Y.copy(w.sqrt(hint)) - Y.mul(D2) - - D2.mul(t) - w.imul(RIADZ) - - X1.copy(NewFPbig(NewBIGints(CURVE_HTPC))) - hint.mul(X1) - - Y3.copy(w.sqrt(hint)) - Y3.mul(D2) - - X2.cmove(X3,1-qr) - Y.cmove(Y3,1-qr) -*/ - ne:=Y.sign()^sgn - w.copy(Y); w.neg(); w.norm() - Y.cmove(w,ne) - - if HTC_ISO!=0 { -/* CAHCZS - k:=0 - isox:=HTC_ISO - isoy:=3*(isox-1)/2 - - //xnum - xnum:=NewFPbig(NewBIGints(PC[k])); k+=1 - for i:=0;i>5 - P:=NewECP2fp2(rx,0) - cmp:=P.y.islarger() - if (sgn==1 && cmp!=1) || (sgn==0 && cmp==1) { + ry := FP2_fromBytes(t[:]) + return NewECP2fp2s(rx, ry) + } else { + sgn := (b[0] & 0x20) >> 5 + P := NewECP2fp2(rx, 0) + cmp := P.y.islarger() + if (sgn == 1 && cmp != 1) || (sgn == 0 && cmp == 1) { P.neg() } - return P; - } - } else { - for i:=0;i= 0; i-- { Q.selector(W, int32(w[i])) P.dbl() @@ -588,7 +589,6 @@ func (E *ECP2) Mul(e *BIG) *ECP2 { return E.mul(e) } - /* clear cofactor */ func (E *ECP2) Cfp() { var T, K, xQ, x2Q *ECP2 @@ -649,7 +649,6 @@ func (E *ECP2) Cfp() { } } - /* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3 */ // Bos & Costello https://eprint.iacr.org/2013/458.pdf // Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf @@ -750,7 +749,7 @@ func ECP2_hap2point(h *BIG) *ECP2 { var Q *ECP2 for true { X = NewFP2bigs(one, x) - Q = NewECP2fp2(X,0) + Q = NewECP2fp2(X, 0) if !Q.Is_infinity() { break } @@ -761,169 +760,169 @@ func ECP2_hap2point(h *BIG) *ECP2 { } /* Constant time Map to Point */ - func ECP2_map2point(H *FP2) *ECP2 { - // Shallue and van de Woestijne +func ECP2_map2point(H *FP2) *ECP2 { + // Shallue and van de Woestijne var Q *ECP2 - NY:=NewFP2int(1) - T:=NewFP2copy(H) /**/ - sgn:=T.sign() /**/ + NY := NewFP2int(1) + T := NewFP2copy(H) /**/ + sgn := T.sign() /**/ if HTC_ISO_G2 == 0 { -/* */ - Z:=NewFPint(RIADZG2A); - X1:=NewFP2fp(Z) - X3:=NewFP2copy(X1) - A:=RHS2(X1) - W:=NewFP2copy(A) - if (RIADZG2A==-1 && RIADZG2B==0 && SEXTIC_TWIST==M_TYPE && CURVE_B_I==4) { // special case for BLS12381 - W.copy(NewFP2ints(2,1)) - } else { - W.sqrt(nil) - } - s:=NewFPbig(NewBIGints(SQRTm3)) - Z.mul(s) - - T.sqr() - Y:=NewFP2copy(A); Y.mul(T) - T.copy(NY); T.add(Y); T.norm() - Y.rsub(NY); Y.norm() - NY.copy(T); NY.mul(Y); - - NY.pmul(Z) - NY.inverse(nil) - - W.pmul(Z) - if (W.sign()==1) { - W.neg() - W.norm() - } - W.pmul(Z) - W.mul(H); W.mul(Y); W.mul(NY) - - X1.neg(); X1.norm(); X1.div2() - X2:=NewFP2copy(X1) - X1.sub(W); X1.norm() - X2.add(W); X2.norm() - A.add(A); A.add(A); A.norm() - T.sqr(); T.mul(NY); T.sqr() - A.mul(T) - X3.add(A); X3.norm() - - Y.copy(RHS2(X2)) - X3.cmove(X2,Y.qr(nil)) - Y.copy(RHS2(X1)) - X3.cmove(X1,Y.qr(nil)) - Y.copy(RHS2(X3)) - Y.sqrt(nil) - - ne:=Y.sign()^sgn - W.copy(Y); W.neg(); W.norm() - Y.cmove(W,ne) - - Q=NewECP2fp2s(X3,Y) -/* */ + /* */ + Z:=NewFPint(RIADZG2A); + X1:=NewFP2fp(Z) + X3:=NewFP2copy(X1) + A:=RHS2(X1) + W:=NewFP2copy(A) + if (RIADZG2A==-1 && RIADZG2B==0 && SEXTIC_TWIST==M_TYPE && CURVE_B_I==4) { // special case for BLS12381 + W.copy(NewFP2ints(2,1)) + } else { + W.sqrt(nil) + } + s:=NewFPbig(NewBIGints(SQRTm3)) + Z.mul(s) + + T.sqr() + Y:=NewFP2copy(A); Y.mul(T) + T.copy(NY); T.add(Y); T.norm() + Y.rsub(NY); Y.norm() + NY.copy(T); NY.mul(Y); + + NY.pmul(Z) + NY.inverse(nil) + + W.pmul(Z) + if (W.sign()==1) { + W.neg() + W.norm() + } + W.pmul(Z) + W.mul(H); W.mul(Y); W.mul(NY) + + X1.neg(); X1.norm(); X1.div2() + X2:=NewFP2copy(X1) + X1.sub(W); X1.norm() + X2.add(W); X2.norm() + A.add(A); A.add(A); A.norm() + T.sqr(); T.mul(NY); T.sqr() + A.mul(T) + X3.add(A); X3.norm() + + Y.copy(RHS2(X2)) + X3.cmove(X2,Y.qr(nil)) + Y.copy(RHS2(X1)) + X3.cmove(X1,Y.qr(nil)) + Y.copy(RHS2(X3)) + Y.sqrt(nil) + + ne:=Y.sign()^sgn + W.copy(Y); W.neg(); W.norm() + Y.cmove(W,ne) + + Q=NewECP2fp2s(X3,Y) + /* */ } else { -/* CAHCZS - Q=NewECP2() - Ad:=NewFP2bigs(NewBIGints(CURVE_Adr), NewBIGints(CURVE_Adi)) - Bd:=NewFP2bigs(NewBIGints(CURVE_Bdr), NewBIGints(CURVE_Bdi)) - ZZ:=NewFP2ints(RIADZG2A,RIADZG2B) - hint:=NewFP() - - T.sqr() - T.mul(ZZ) - W:=NewFP2copy(T) - W.add(NY); W.norm() - - W.mul(T) - D:=NewFP2copy(Ad) - D.mul(W) - - W.add(NY); W.norm() - W.mul(Bd); - W.neg(); W.norm() - - X2:=NewFP2copy(W) - X3:=NewFP2copy(T) - X3.mul(X2) - - GX1:=NewFP2copy(X2); GX1.sqr() - D2:=NewFP2copy(D); D2.sqr() - - W.copy(Ad); W.mul(D2); GX1.add(W); GX1.norm(); GX1.mul(X2); D2.mul(D); W.copy(Bd); W.mul(D2); GX1.add(W); GX1.norm() // x^3+Ax+b - - W.copy(GX1); W.mul(D) - qr:=W.qr(hint) - D.copy(W); D.inverse(hint) - D.mul(GX1) - X2.mul(D) - X3.mul(D) - T.mul(H) - D2.copy(D); D2.sqr() - - D.copy(D2); D.mul(T) - T.copy(W); T.mul(ZZ) - - s:=NewFPbig(NewBIGints(CURVE_HTPC2)) - s.mul(hint); - - X2.cmove(X3,1-qr) - W.cmove(T,1-qr) - D2.cmove(D,1-qr) - hint.cmove(s,1-qr) - - Y:=NewFP2copy(W); Y.sqrt(hint) - Y.mul(D2) - - ne:=Y.sign()^sgn - W.copy(Y); W.neg(); W.norm() - Y.cmove(W,ne) - - k:=0 - isox:=HTC_ISO_G2 - isoy:=3*(isox-1)/2 - -//xnum - xnum:=NewFP2bigs(NewBIGints(PCR[k]),NewBIGints(PCI[k])); k+=1 - for i:=0;i 0 { // if not prehash and no context, omit dom2() + domain := dom("SigFP256BN no FP256BN collisions", ph, byte(cl)) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < int(cl); i++ { + sh.Process(ctx[i]) + } + } + for i := 0; i < b; i++ { + sh.Process(R[i]) + } + for i := 0; i < b; i++ { + sh.Process(Q[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + h := sh.Hash() + eddsa_reverse(64, h) + return DBIG_fromBytes(h) + } else { // for ed448? + domain := dom("SigFP256BN", ph, byte(cl)) + h := make([]byte, 2*b) + sh := core.NewSHA3(core.SHA3_SHAKE256) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < cl; i++ { + sh.Process(ctx[i]) + } + for i := 0; i < b; i++ { + sh.Process(R[i]) + } + for i := 0; i < b; i++ { + sh.Process(Q[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + sh.Shake(h, 2*b) + eddsa_reverse(2*b, h) + return DBIG_fromBytes(h) + } +} + +func getR(ph bool, b int, digest []byte, ctx []byte, M []byte) *DBIG { + cl := 0 + if ctx != nil { + cl = len(ctx) + } + if AESKEY <= 16 { // Ed25519?? + sh := core.NewHASH512() + if ph || cl > 0 { // if not prehash and no context, omit dom2() + domain := dom("SigFP256BN no FP256BN collisions", ph, byte(cl)) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < cl; i++ { + sh.Process(ctx[i]) + } + } + for i := b; i < 2*b; i++ { + sh.Process(digest[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + h := sh.Hash() + eddsa_reverse(64, h) + return DBIG_fromBytes(h) + } else { // for ed448? + domain := dom("SigFP256BN", ph, byte(cl)) + sh := core.NewSHA3(core.SHA3_SHAKE256) + h := make([]byte, 2*b) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < cl; i++ { + sh.Process(ctx[i]) + } + for i := b; i < 2*b; i++ { + sh.Process(digest[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + sh.Shake(h, 2*b) + eddsa_reverse(2*b, h) + return DBIG_fromBytes(h) + } +} + +// encode integer (little endian) +func encode_int(x *BIG, w []byte) int { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + w[0] = 0 + x.tobytearray(w, index) + eddsa_reverse(b, w) + return b +} + +// encode point +func encode(P *ECP, w []byte) { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + x := P.GetX() + y := P.GetY() + encode_int(y, w) + w[b-1] |= byte(x.parity() << 7) +} + +// get sign +func getsign(x []byte) int { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + if (x[b-1] & 0x80) != 0 { + return 1 + } else { + return 0 + } +} + +// decode integer (little endian) +func decode_int(strip_sign bool, ei []byte) *BIG { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + r := make([]byte, b) + for i := 0; i < b; i++ { + r[i] = ei[i] + } + eddsa_reverse(b, r) + if strip_sign { + r[0] &= 0x7f + } + return BIG_frombytearray(r, index) +} + +// decode compressed point +func decode(W []byte) *ECP { + sign := getsign(W) // lsb of x + y := decode_int(true, W) + one := NewFPint(1) + hint := NewFP() + x := NewFPbig(y) + x.sqr() + d := NewFPcopy(x) + x.sub(one) + x.norm() + t := NewFPbig(NewBIGints(CURVE_B)) + d.mul(t) + if CURVE_A == 1 { + d.sub(one) + } + if CURVE_A == -1 { + d.add(one) + } + d.norm() + // inverse square root trick for sqrt(x/d) + t.copy(x) + t.sqr() + x.mul(t) + x.mul(d) + if x.qr(hint) != 1 { + return NewECP() + } + d.copy(x.sqrt(hint)) + x.inverse(hint) + x.mul(d) + x.mul(t) + x.reduce() + if x.redc().parity() != sign { + x.neg() + } + x.norm() + return NewECPbigs(x.redc(), y) +} + +/* Calculate a public/private EC GF(p) key pair. Q=D.G mod EC(p), + * where D is the secret key and Q is the public key + * and G is fixed generator. + * RNG is a cryptographically strong RNG + * If RNG==NULL, D is provided externally + */ +func KEY_PAIR_GENERATE(RNG *core.RAND, D []byte, Q []byte) int { + res := 0 + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + G := ECP_generator() + + if RNG != nil { + for i := 0; i < b; i++ { + D[i] = byte(RNG.GetByte()) + } + } + digest := h(D) + + // reverse bytes for little endian + eddsa_reverse(b, digest) + s := BIG_frombytearray(digest, index) + rfc7748(s) + G.Copy(G.mul(s)) + encode(G, Q) + return res +} + +// Generate a signature using key pair (D,Q) on message M +// Set ph=true if message has already been pre-hashed +// if ph=false, then context should be NULL for ed25519. However RFC8032 mode ed25519ctx is supported by supplying a non-NULL or non-empty context +func SIGNATURE(ph bool, D []byte, ctx []byte, M []byte, SIG []byte) int { + digest := h(D) // hash of private key + res := 0 + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + S := make([]byte, b) + Q := make([]byte, b) + KEY_PAIR_GENERATE(nil, D, Q[:]) + + q := NewBIGints(CURVE_Order) + if len(D) != len(Q) || len(D) != b { + res = EDDSA_INVALID_PUBLIC_KEY + } + if res == 0 { + dr := getR(ph, b, digest, ctx, M) + sr := dr.Mod(q) + R := ECP_generator().mul(sr) + encode(R, S[:]) + for i := 0; i < b; i++ { + SIG[i] = S[i] + } + // reverse bytes for little endian + eddsa_reverse(b, digest) + s := BIG_frombytearray(digest, index) + RFC7748(s) + dr = h2(ph, ctx, SIG, Q, M) + sd := dr.Mod(q) + encode_int(Modadd(sr, Modmul(s, sd, q), q), S) + for i := 0; i < b; i++ { + SIG[b+i] = S[i] + } + } + return res +} + +func VERIFY(ph bool, Q []byte, ctx []byte, M []byte, SIG []byte) bool { + lg := 0 + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + S := make([]byte, b) + c := CURVE_Cof_I + for c != 1 { + lg++ + c /= 2 + } + q := NewBIGints(CURVE_Order) + R := decode(SIG) + if R.Is_infinity() { + return false + } + for i := 0; i < b; i++ { + S[i] = SIG[b+i] + } + t := decode_int(false, S) + if Comp(t, q) >= 0 { + return false + } + du := h2(ph, ctx, SIG, Q, M) + su := du.Mod(q) + + G := ECP_generator() + QD := decode(Q) + if QD.Is_infinity() { + return false + } + QD.Neg() + for i := 0; i < lg; i++ { // use cofactor 2^c + G.dbl() + QD.dbl() + R.dbl() + } + + if !G.Mul2(t, QD, su).Equals(R) { + return false + } + return true +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/EDDSA_32.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/EDDSA_32.go new file mode 100644 index 00000000000..e37a1a997d8 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/EDDSA_32.go @@ -0,0 +1,413 @@ +//go:build 386 || arm + +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* EDDSA API Functions */ + +package FP256BN + +import "github.com/hyperledger/fabric-amcl/core" + +const EDDSA_INVALID_PUBLIC_KEY int = -2 + +//const EDDSA_ERROR int = -3 + +// Transform a point multiplier to rfc7748 form +func rfc7748(r *BIG) { + lg := 0 + t := NewBIGint(1) + c := CURVE_Cof_I + for c != 1 { + lg++ + c /= 2 + } + n := uint(8*EGS - lg + 1) + r.mod2m(n) + t.shl(n) + r.add(t) + c = r.lastbits(lg) + r.dec(c) +} + +// reverse first n bytes of buff - for little endian +func eddsa_reverse(n int, buff []byte) { + for i := 0; i < n/2; i++ { + ch := buff[i] + buff[i] = buff[n-i-1] + buff[n-i-1] = ch + } +} + +// dom - domain function +func dom(pp string, ph bool, cl byte) []byte { + PP := []byte(pp) + n := len(PP) + dom := make([]byte, n+2) + for i := 0; i < n; i++ { + dom[i] = PP[i] + } + if ph { + dom[n] = 1 + } else { + dom[n] = 0 + } + dom[n+1] = cl + return dom +} + +func h(S []byte) []byte { + n := len(S) + if AESKEY <= 16 { // for ed25519? + sh := core.NewHASH512() + for i := 0; i < n; i++ { + sh.Process(S[i]) + } + return sh.Hash() + } else { // for ed448? + digest := make([]byte, 2*n) + sh := core.NewSHA3(core.SHA3_SHAKE256) + for i := 0; i < n; i++ { + sh.Process(S[i]) + } + sh.Shake(digest[:], 2*n) + return digest + } +} + +func h2(ph bool, ctx []byte, R []byte, Q []byte, M []byte) *DBIG { + b := len(Q) + cl := 0 + if ctx != nil { + cl = len(ctx) + } + if AESKEY <= 16 { // Ed25519?? + sh := core.NewHASH512() + if ph || cl > 0 { // if not prehash and no context, omit dom2() + domain := dom("SigFP256BN no FP256BN collisions", ph, byte(cl)) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < int(cl); i++ { + sh.Process(ctx[i]) + } + } + for i := 0; i < b; i++ { + sh.Process(R[i]) + } + for i := 0; i < b; i++ { + sh.Process(Q[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + h := sh.Hash() + eddsa_reverse(64, h) + return DBIG_fromBytes(h) + } else { // for ed448? + domain := dom("SigFP256BN", ph, byte(cl)) + h := make([]byte, 2*b) + sh := core.NewSHA3(core.SHA3_SHAKE256) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < cl; i++ { + sh.Process(ctx[i]) + } + for i := 0; i < b; i++ { + sh.Process(R[i]) + } + for i := 0; i < b; i++ { + sh.Process(Q[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + sh.Shake(h, 2*b) + eddsa_reverse(2*b, h) + return DBIG_fromBytes(h) + } +} + +func getR(ph bool, b int, digest []byte, ctx []byte, M []byte) *DBIG { + cl := 0 + if ctx != nil { + cl = len(ctx) + } + if AESKEY <= 16 { // Ed25519?? + sh := core.NewHASH512() + if ph || cl > 0 { // if not prehash and no context, omit dom2() + domain := dom("SigFP256BN no FP256BN collisions", ph, byte(cl)) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < cl; i++ { + sh.Process(ctx[i]) + } + } + for i := b; i < 2*b; i++ { + sh.Process(digest[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + h := sh.Hash() + eddsa_reverse(64, h) + return DBIG_fromBytes(h) + } else { // for ed448? + domain := dom("SigFP256BN", ph, byte(cl)) + sh := core.NewSHA3(core.SHA3_SHAKE256) + h := make([]byte, 2*b) + for i := 0; i < len(domain); i++ { + sh.Process(domain[i]) + } + for i := 0; i < cl; i++ { + sh.Process(ctx[i]) + } + for i := b; i < 2*b; i++ { + sh.Process(digest[i]) + } + for i := 0; i < len(M); i++ { + sh.Process(M[i]) + } + sh.Shake(h, 2*b) + eddsa_reverse(2*b, h) + return DBIG_fromBytes(h) + } +} + +// encode integer (little endian) +func encode_int(x *BIG, w []byte) int { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + w[0] = 0 + x.tobytearray(w, index) + eddsa_reverse(b, w) + return b +} + +// encode point +func encode(P *ECP, w []byte) { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + x := P.GetX() + y := P.GetY() + encode_int(y, w) + w[b-1] |= byte(x.parity() << 7) +} + +// get sign +func getsign(x []byte) int { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + if (x[b-1] & 0x80) != 0 { + return 1 + } else { + return 0 + } +} + +// decode integer (little endian) +func decode_int(strip_sign bool, ei []byte) *BIG { + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + r := make([]byte, b) + for i := 0; i < b; i++ { + r[i] = ei[i] + } + eddsa_reverse(b, r) + if strip_sign { + r[0] &= 0x7f + } + return BIG_frombytearray(r, index) +} + +// decode compressed point +func decode(W []byte) *ECP { + sign := getsign(W) // lsb of x + y := decode_int(true, W) + one := NewFPint(1) + hint := NewFP() + x := NewFPbig(y) + x.sqr() + d := NewFPcopy(x) + x.sub(one) + x.norm() + t := NewFPbig(NewBIGints(CURVE_B)) + d.mul(t) + if CURVE_A == 1 { + d.sub(one) + } + if CURVE_A == -1 { + d.add(one) + } + d.norm() + // inverse square root trick for sqrt(x/d) + t.copy(x) + t.sqr() + x.mul(t) + x.mul(d) + if x.qr(hint) != 1 { + return NewECP() + } + d.copy(x.sqrt(hint)) + x.inverse(hint) + x.mul(d) + x.mul(t) + x.reduce() + if x.redc().parity() != sign { + x.neg() + } + x.norm() + return NewECPbigs(x.redc(), y) +} + +/* Calculate a public/private EC GF(p) key pair. Q=D.G mod EC(p), + * where D is the secret key and Q is the public key + * and G is fixed generator. + * RNG is a cryptographically strong RNG + * If RNG==NULL, D is provided externally + */ +func KEY_PAIR_GENERATE(RNG *core.RAND, D []byte, Q []byte) int { + res := 0 + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + + G := ECP_generator() + + if RNG != nil { + for i := 0; i < b; i++ { + D[i] = byte(RNG.GetByte()) + } + } + digest := h(D) + + // reverse bytes for little endian + eddsa_reverse(b, digest) + s := BIG_frombytearray(digest, index) + rfc7748(s) + G.Copy(G.mul(s)) + encode(G, Q) + return res +} + +// Generate a signature using key pair (D,Q) on message M +// Set ph=true if message has already been pre-hashed +// if ph=false, then context should be NULL for ed25519. However RFC8032 mode ed25519ctx is supported by supplying a non-NULL or non-empty context +func SIGNATURE(ph bool, D []byte, ctx []byte, M []byte, SIG []byte) int { + digest := h(D) // hash of private key + res := 0 + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + S := make([]byte, b) + Q := make([]byte, b) + KEY_PAIR_GENERATE(nil, D, Q[:]) + + q := NewBIGints(CURVE_Order) + if len(D) != len(Q) || len(D) != b { + res = EDDSA_INVALID_PUBLIC_KEY + } + if res == 0 { + dr := getR(ph, b, digest, ctx, M) + sr := dr.Mod(q) + R := ECP_generator().mul(sr) + encode(R, S[:]) + for i := 0; i < b; i++ { + SIG[i] = S[i] + } + // reverse bytes for little endian + eddsa_reverse(b, digest) + s := BIG_frombytearray(digest, index) + RFC7748(s) + dr = h2(ph, ctx, SIG, Q, M) + sd := dr.Mod(q) + encode_int(Modadd(sr, Modmul(s, sd, q), q), S) + for i := 0; i < b; i++ { + SIG[b+i] = S[i] + } + } + return res +} + +func VERIFY(ph bool, Q []byte, ctx []byte, M []byte, SIG []byte) bool { + lg := 0 + index := 0 + if 8*MODBYTES == MODBITS { + index = 1 // extra byte needed for compression + } + b := int(MODBYTES) + index + S := make([]byte, b) + c := CURVE_Cof_I + for c != 1 { + lg++ + c /= 2 + } + q := NewBIGints(CURVE_Order) + R := decode(SIG) + if R.Is_infinity() { + return false + } + for i := 0; i < b; i++ { + S[i] = SIG[b+i] + } + t := decode_int(false, S) + if Comp(t, q) >= 0 { + return false + } + du := h2(ph, ctx, SIG, Q, M) + su := du.Mod(q) + + G := ECP_generator() + QD := decode(Q) + if QD.Is_infinity() { + return false + } + QD.Neg() + for i := 0; i < lg; i++ { // use cofactor 2^c + G.dbl() + QD.dbl() + R.dbl() + } + + if !G.Mul2(t, QD, su).Equals(R) { + return false + } + return true +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP.go index 5d7a2c21928..acb9e2eff98 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * @@ -21,6 +23,7 @@ /* CLINT mod p functions */ package FP256BN + import "github.com/hyperledger/fabric-amcl/core" type FP struct { @@ -41,7 +44,8 @@ func NewFPint(a int) *FP { F := new(FP) if a < 0 { m := NewBIGints(Modulus) - m.inc(a); m.norm(); + m.inc(a) + m.norm() F.x = NewBIGcopy(m) } else { F.x = NewBIGint(a) @@ -66,7 +70,7 @@ func NewFPcopy(a *FP) *FP { func NewFPrand(rng *core.RAND) *FP { m := NewBIGints(Modulus) - w := Randomnum(m,rng) + w := Randomnum(m, rng) F := NewFPbig(w) return F } @@ -135,7 +139,7 @@ func mod(d *DBIG) *BIG { return b } - if MODTYPE == GENERALISED_MERSENNE { // GoldiLocks only + if MODTYPE == GENERALISED_MERSENNE { // Ed448 only t := d.split(MODBITS) b := NewBIGdcopy(d) b.add(t) @@ -154,7 +158,7 @@ func mod(d *DBIG) *BIG { b.w[NLEN-1] &= TMASK b.w[0] += carry - ix := 224/int(BASEBITS) + ix := 224 / int(BASEBITS) b.w[ix] += carry << (224 % BASEBITS) b.norm() return b @@ -222,13 +226,14 @@ func (F *FP) iszilch() bool { } func (F *FP) islarger() int { - if F.iszilch() { - return 0; + if F.iszilch() { + return 0 } - sx:= NewBIGints(Modulus) - fx:=F.redc(); - sx.sub(fx); sx.norm() - return Comp(fx,sx) + sx := NewBIGints(Modulus) + fx := F.redc() + sx.sub(fx) + sx.norm() + return Comp(fx, sx) } func (F *FP) ToBytes(b []byte) { @@ -236,12 +241,12 @@ func (F *FP) ToBytes(b []byte) { } func FP_fromBytes(b []byte) *FP { - t:=FromBytes(b) + t := FromBytes(b) return NewFPbig(t) } func (F *FP) isunity() bool { - W:=NewFPcopy(F) + W := NewFPcopy(F) W.reduce() return W.redc().isunity() } @@ -270,13 +275,13 @@ func (F *FP) sign() int { m := NewBIGints(Modulus) m.dec(1) m.fshr(1) - n := NewFPcopy(F); + n := NewFPcopy(F) n.reduce() w := n.redc() - cp:=Comp(w,m) - return ((cp+1)&2)>>1 + cp := Comp(w, m) + return ((cp + 1) & 2) >> 1 } else { - W:=NewFPcopy(F) + W := NewFPcopy(F) W.reduce() return W.redc().parity() } @@ -391,16 +396,16 @@ func (F *FP) rsub(b *FP) { /* this/=2 mod Modulus */ func (F *FP) div2() { - p:=NewBIGints(Modulus) - pr:=F.x.parity() - w:=NewBIGcopy(F.x) + p := NewBIGints(Modulus) + pr := F.x.parity() + w := NewBIGcopy(F.x) F.x.fshr(1) - w.add(p); w.norm() + w.add(p) + w.norm() w.fshr(1) - F.x.cmove(w,pr) + F.x.cmove(w, pr) } - /* return jacobi symbol (this/Modulus) */ func (F *FP) jacobi() int { w := F.redc() @@ -486,17 +491,17 @@ func (F *FP) fpow() *FP { e := int(PM1D2) n = int(MODBITS) - if MODTYPE == GENERALISED_MERSENNE { // Goldilocks ONLY + if MODTYPE == GENERALISED_MERSENNE { // Ed448 ONLY n /= 2 } - n-=(e+1) - c=(int(MConst)+(1<0 { + for nd > 0 { r.sqr() nd-- } @@ -589,53 +594,53 @@ func (F *FP) fpow() *FP { // calculates r=x^(p-1-2^e)/2^{e+1) where 2^e|p-1 func (F *FP) progen() { - if (MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE) { + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { F.copy(F.fpow()) return } - e:=uint(PM1D2) + e := uint(PM1D2) m := NewBIGints(Modulus) - m.dec(1); - m.shr(e); - m.dec(1); - m.fshr(1); - F.copy(F.pow(m)); + m.dec(1) + m.shr(e) + m.dec(1) + m.fshr(1) + F.copy(F.pow(m)) } /* this=1/this mod Modulus */ func (F *FP) inverse(h *FP) { - e:=int(PM1D2) - F.norm() - s:=NewFPcopy(F) - for i:=0;i1;k-- { - for j:=1;j 1; k-- { + for j := 1; j < k-1; j++ { b.sqr() } var u int if b.isunity() { - u=0 + u = 0 } else { - u=1 + u = 1 } - g.copy(r); g.mul(v) - r.cmove(g,u) + g.copy(r) + g.mul(v) + r.cmove(g, u) v.sqr() - g.copy(t); g.mul(v) - t.cmove(g,u) + g.copy(t) + g.mul(v) + t.cmove(g, u) b.copy(t) } - sgn:=r.sign() - nr:=NewFPcopy(r) - nr.neg(); nr.norm() - r.cmove(nr,sgn) + sgn := r.sign() + nr := NewFPcopy(r) + nr.neg() + nr.norm() + r.cmove(nr, sgn) return r } -func (F *FP) invsqrt(i *FP,s *FP) int { - h:=NewFP() - qr:=F.qr(h) +func (F *FP) invsqrt(i *FP, s *FP) int { + h := NewFP() + qr := F.qr(h) s.copy(F.sqrt(h)) i.copy(F) i.inverse(h) @@ -701,18 +709,18 @@ func (F *FP) invsqrt(i *FP,s *FP) int { // Two for the price of one - See Hamburg https://eprint.iacr.org/2012/309.pdf // Calculate inverse of i and square root of s, return QR -func FP_tpo(i *FP,s *FP) int { - w:=NewFPcopy(s) - t:=NewFPcopy(i) +func FP_tpo(i *FP, s *FP) int { + w := NewFPcopy(s) + t := NewFPcopy(i) w.mul(i) t.mul(w) - qr:=t.invsqrt(i,s) + qr := t.invsqrt(i, s) i.mul(w) s.mul(i) return qr } -/* return sqrt(this) mod Modulus +/* return sqrt(this) mod Modulus func (F *FP) sqrt() *FP { F.reduce() if PM1D2 == 2 { @@ -752,5 +760,3 @@ func (F *FP) sqrt() *FP { return r } } */ - - diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP12.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP12.go index e807636275d..579ef10b926 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP12.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP12.go @@ -832,39 +832,39 @@ func (F *FP12) trace() *FP4 { /* convert from byte array to FP12 */ func FP12_fromBytes(w []byte) *FP12 { - var t [4*int(MODBYTES)]byte - MB := 4*int(MODBYTES) + var t [4 * int(MODBYTES)]byte + MB := 4 * int(MODBYTES) - for i:=0;i= 1; i-- { w.usqr() diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP2.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP2.go index 9837002749a..b7cd2cb5a46 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP2.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP2.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * @@ -22,8 +24,8 @@ /* FP2 elements are of the form a+ib, where i is sqrt(-1) */ package FP256BN -import "github.com/hyperledger/fabric-amcl/core" +import "github.com/hyperledger/fabric-amcl/core" type FP2 struct { a *FP @@ -88,7 +90,7 @@ func NewFP2big(c *BIG) *FP2 { } func NewFP2rand(rng *core.RAND) *FP2 { - F := NewFP2fps(NewFPrand(rng),NewFPrand(rng)) + F := NewFP2fps(NewFPrand(rng), NewFPrand(rng)) return F } @@ -110,11 +112,11 @@ func (F *FP2) iszilch() bool { } func (F *FP2) islarger() int { - if F.iszilch() { - return 0; + if F.iszilch() { + return 0 } - cmp:=F.b.islarger() - if cmp!=0 { + cmp := F.b.islarger() + if cmp != 0 { return cmp } return F.a.islarger() @@ -123,28 +125,28 @@ func (F *FP2) islarger() int { func (F *FP2) ToBytes(bf []byte) { var t [int(MODBYTES)]byte MB := int(MODBYTES) - F.b.ToBytes(t[:]); - for i:=0;i int64(FEXCESS) { + if F.a.XES > 1 { + F.a.reduce() + } + if F.b.XES > 1 { + F.b.reduce() + } + } + + pR := NewDBIG() + C := NewBIGcopy(F.a.x) + D := NewBIGcopy(y.a.x) + p := NewBIGints(Modulus) + + pR.ucopy(p) + + A := mul(F.a.x, y.a.x) + B := mul(F.b.x, y.b.x) + + C.add(F.b.x) + C.norm() + D.add(y.b.x) + D.norm() + + E := mul(C, D) + FF := NewDBIGcopy(A) + FF.add(B) + B.rsub(pR) + + A.add(B) + A.norm() + E.sub(FF) + E.norm() + + F.a.x.copy(mod(A)) + F.a.XES = 3 + F.b.x.copy(mod(E)) + F.b.XES = 2 + +} + +/* + func (F *FP2) pow(b *BIG) { + w := NewFP2copy(F); + r := NewFP2int(1) + z := NewBIGcopy(b) + for true { + bt := z.parity() + z.shr(1) + if bt==1 { + r.mul(w) + } + if z.iszilch() {break} + w.sqr() + } + r.reduce() + F.copy(r) + } +*/ +func (F *FP2) qr(h *FP) int { + c := NewFP2copy(F) + c.conj() + c.mul(F) + return c.a.qr(h) +} + +/* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) */ +func (F *FP2) sqrt(h *FP) { + if F.iszilch() { + return + } + w1 := NewFPcopy(F.b) + w2 := NewFPcopy(F.a) + w3 := NewFP() + w4 := NewFP() + hint := NewFP() + w1.sqr() + w2.sqr() + w1.add(w2) + w1.norm() + + w1 = w1.sqrt(h) + w2.copy(F.a) + w3.copy(F.a) + + w2.add(w1) + w2.norm() + w2.div2() + + w1.copy(F.b) + w1.div2() + qr := w2.qr(hint) + + // tweak hint + w3.copy(hint) + w3.neg() + w3.norm() + w4.copy(w2) + w4.neg() + w4.norm() + + w2.cmove(w4, 1-qr) + hint.cmove(w3, 1-qr) + + F.a.copy(w2.sqrt(hint)) + w3.copy(w2) + w3.inverse(hint) + w3.mul(F.a) + F.b.copy(w3) + F.b.mul(w1) + w4.copy(F.a) + + F.a.cmove(F.b, 1-qr) + F.b.cmove(w4, 1-qr) + + /* + F.a.copy(w2.sqrt(hint)) + w3.copy(w2); w3.inverse(hint) + w3.mul(F.a) + F.b.copy(w3); F.b.mul(w1) + + hint.neg(); hint.norm() + w2.neg(); w2.norm() + + w4.copy(w2.sqrt(hint)) + w3.copy(w2); w3.inverse(hint) + w3.mul(w4) + w3.mul(w1) + + F.a.cmove(w3,1-qr) + F.b.cmove(w4,1-qr) + */ + + sgn := F.sign() + nr := NewFP2copy(F) + nr.neg() + nr.norm() + F.cmove(nr, sgn) +} + +/* output to hex string */ +func (F *FP2) ToString() string { + return ("[" + F.a.ToString() + "," + F.b.ToString() + "]") +} + +/* output to hex string */ +func (F *FP2) toString() string { + return ("[" + F.a.ToString() + "," + F.b.ToString() + "]") +} + +/* this=1/this */ +func (F *FP2) inverse(h *FP) { + F.norm() + w1 := NewFPcopy(F.a) + w2 := NewFPcopy(F.b) + + w1.sqr() + w2.sqr() + w1.add(w2) + w1.inverse(h) + F.a.mul(w1) + w1.neg() + w1.norm() + F.b.mul(w1) +} + +/* this/=2 */ +func (F *FP2) div2() { + F.a.div2() + F.b.div2() +} + +/* this*=sqrt(-1) */ +func (F *FP2) times_i() { + z := NewFPcopy(F.a) + F.a.copy(F.b) + F.a.neg() + F.b.copy(z) +} + +/* w*=(1+sqrt(-1)) */ +/* where X*2-(2^i+sqrt(-1)) is irreducible for FP4 */ +func (F *FP2) mul_ip() { + t := NewFP2copy(F) + i := QNRI + F.times_i() + for i > 0 { + t.add(t) + t.norm() + i-- + } + F.add(t) + + if TOWER == POSITOWER { + F.norm() + F.neg() + } + +} + +/* w/=(2^i+sqrt(-1)) */ +func (F *FP2) div_ip() { + z := NewFP2ints(1<= 0; i-- { + if v.bit(i) != 1 { + t.copy(b) + sf.conj() + c.conj() + b.xtr_A(a, sf, c) + sf.conj() + c.copy(t) + c.xtr_D() + a.xtr_D() + } else { + t.copy(a) + t.conj() + a.copy(b) + a.xtr_D() + b.xtr_A(c, sf, t) + c.xtr_D() + } + } + if par == 0 { + r.copy(c) + } else { + r.copy(b) + } + r.reduce() + return r +} + +/* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */ +func (F *FP4) xtr_pow2(ck *FP4, ckml *FP4, ckm2l *FP4, a *BIG, b *BIG) *FP4 { + + e := NewBIGcopy(a) + d := NewBIGcopy(b) + w := NewBIGint(0) + e.norm() + d.norm() + + cu := NewFP4copy(ck) // can probably be passed in w/o copying + cv := NewFP4copy(F) + cumv := NewFP4copy(ckml) + cum2v := NewFP4copy(ckm2l) + r := NewFP4() + t := NewFP4() + + f2 := 0 + for d.parity() == 0 && e.parity() == 0 { + d.fshr(1) + e.fshr(1) + f2++ + } + + for Comp(d, e) != 0 { + if Comp(d, e) > 0 { + w.copy(e) + w.imul(4) + w.norm() + if Comp(d, w) <= 0 { + w.copy(d) + d.copy(e) + e.rsub(w) + e.norm() + + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cum2v.copy(cumv) + cum2v.conj() + cumv.copy(cv) + cv.copy(cu) + cu.copy(t) + } else { + if d.parity() == 0 { + d.fshr(1) + r.copy(cum2v) + r.conj() + t.copy(cumv) + t.xtr_A(cu, cv, r) + cum2v.copy(cumv) + cum2v.xtr_D() + cumv.copy(t) + cu.xtr_D() + } else { + if e.parity() == 1 { + d.sub(e) + d.norm() + d.fshr(1) + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cu.xtr_D() + cum2v.copy(cv) + cum2v.xtr_D() + cum2v.conj() + cv.copy(t) + } else { + w.copy(d) + d.copy(e) + d.fshr(1) + e.copy(w) + t.copy(cumv) + t.xtr_D() + cumv.copy(cum2v) + cumv.conj() + cum2v.copy(t) + cum2v.conj() + t.copy(cv) + t.xtr_D() + cv.copy(cu) + cu.copy(t) + } + } + } + } + if Comp(d, e) < 0 { + w.copy(d) + w.imul(4) + w.norm() + if Comp(e, w) <= 0 { + e.sub(d) + e.norm() + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cum2v.copy(cumv) + cumv.copy(cu) + cu.copy(t) + } else { + if e.parity() == 0 { + w.copy(d) + d.copy(e) + d.fshr(1) + e.copy(w) + t.copy(cumv) + t.xtr_D() + cumv.copy(cum2v) + cumv.conj() + cum2v.copy(t) + cum2v.conj() + t.copy(cv) + t.xtr_D() + cv.copy(cu) + cu.copy(t) + } else { + if d.parity() == 1 { + w.copy(e) + e.copy(d) + w.sub(d) + w.norm() + d.copy(w) + d.fshr(1) + t.copy(cv) + t.xtr_A(cu, cumv, cum2v) + cumv.conj() + cum2v.copy(cu) + cum2v.xtr_D() + cum2v.conj() + cu.copy(cv) + cu.xtr_D() + cv.copy(t) + } else { + d.fshr(1) + r.copy(cum2v) + r.conj() + t.copy(cumv) + t.xtr_A(cu, cv, r) + cum2v.copy(cumv) + cum2v.xtr_D() + cumv.copy(t) + cu.xtr_D() + } + } + } + } + } + r.copy(cv) + r.xtr_A(cu, cumv, cum2v) + for i := 0; i < f2; i++ { + r.xtr_D() + } + r = r.xtr_pow(d) + return r +} + +/* this/=2 */ +func (F *FP4) div2() { + F.a.div2() + F.b.div2() +} + +func (F *FP4) div_i() { + u := NewFP2copy(F.a) + v := NewFP2copy(F.b) + u.div_ip() + F.a.copy(v) + F.b.copy(u) + if TOWER == POSITOWER { + F.neg() + F.norm() + } +} + +/* +func (F *FP4) pow(b *BIG) { + w := NewFP4copy(F); + r := NewFP4int(1) + z := NewBIGcopy(b) + for true { + bt := z.parity() + z.shr(1) + if bt==1 { + r.mul(w) + } + if z.iszilch() {break} + w.sqr() + } + r.reduce(); + F.copy(r); +} +*/ + +/* PFGE24S +// Test for Quadratic Residue +func (F *FP4) qr(h *FP) int { + c := NewFP4copy(F) + c.conj() + c.mul(F) + return c.a.qr(h) +} + +// sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) +func (F *FP4) sqrt(h *FP) { + if F.iszilch() { + return + } + + a := NewFP2copy(F.a) + b := NewFP2() + s := NewFP2copy(F.b) + t := NewFP2copy(F.a) + hint := NewFP() + + s.sqr() + a.sqr() + s.mul_ip() + s.norm() + a.sub(s) + + s.copy(a); s.norm() + s.sqrt(h); + + a.copy(t) + b.copy(t) + + a.add(s) + a.norm() + a.div2() + + + b.copy(F.b); b.div2() + qr:=a.qr(hint) + +// tweak hint - multiply old hint by Norm(1/Beta)^e where Beta is irreducible polynomial + s.copy(a) + twk:=NewFPbig(NewBIGints(TWK)) + twk.mul(hint) + s.div_ip(); s.norm() + + a.cmove(s,1-qr) + hint.cmove(twk,1-qr) + + F.a.copy(a); F.a.sqrt(hint) + s.copy(a); s.inverse(hint) + s.mul(F.a) + F.b.copy(s); F.b.mul(b) + t.copy(F.a); + + F.a.cmove(F.b,1-qr); + F.b.cmove(t,1-qr); + + sgn:=F.sign() + nr:=NewFP4copy(F) + nr.neg(); nr.norm() + F.cmove(nr,sgn) +} +PFGE24F */ diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP_32.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP_32.go new file mode 100644 index 00000000000..542e494e890 --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/FP_32.go @@ -0,0 +1,762 @@ +//go:build 386 || arm + +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Finite Field arithmetic */ +/* CLINT mod p functions */ + +package FP256BN + +import "github.com/hyperledger/fabric-amcl/core" + +type FP struct { + x *BIG + XES int32 +} + +/* Constructors */ + +func NewFP() *FP { + F := new(FP) + F.x = NewBIG() + F.XES = 1 + return F +} + +func NewFPint(a int) *FP { + F := new(FP) + if a < 0 { + m := NewBIGints(Modulus) + m.inc(a) + m.norm() + F.x = NewBIGcopy(m) + } else { + F.x = NewBIGint(a) + } + F.nres() + return F +} + +func NewFPbig(a *BIG) *FP { + F := new(FP) + F.x = NewBIGcopy(a) + F.nres() + return F +} + +func NewFPcopy(a *FP) *FP { + F := new(FP) + F.x = NewBIGcopy(a.x) + F.XES = a.XES + return F +} + +func NewFPrand(rng *core.RAND) *FP { + m := NewBIGints(Modulus) + w := Randomnum(m, rng) + F := NewFPbig(w) + return F +} + +func (F *FP) ToString() string { + F.reduce() + return F.redc().ToString() +} + +/* convert to Montgomery n-residue form */ +func (F *FP) nres() { + if MODTYPE != PSEUDO_MERSENNE && MODTYPE != GENERALISED_MERSENNE { + r := NewBIGints(R2modp) + d := mul(F.x, r) + F.x.copy(mod(d)) + F.XES = 2 + } else { + md := NewBIGints(Modulus) + F.x.Mod(md) + F.XES = 1 + } +} + +/* convert back to regular form */ +func (F *FP) redc() *BIG { + if MODTYPE != PSEUDO_MERSENNE && MODTYPE != GENERALISED_MERSENNE { + d := NewDBIGscopy(F.x) + return mod(d) + } else { + r := NewBIGcopy(F.x) + return r + } +} + +/* reduce a DBIG to a BIG using the appropriate form of the modulus */ + +func mod(d *DBIG) *BIG { + if MODTYPE == PSEUDO_MERSENNE { + t := d.split(MODBITS) + b := NewBIGdcopy(d) + + v := t.pmul(int(MConst)) + + t.add(b) + t.norm() + + tw := t.w[NLEN-1] + t.w[NLEN-1] &= TMASK + t.w[0] += (MConst * ((tw >> TBITS) + (v << (BASEBITS - TBITS)))) + + t.norm() + return t + } + if MODTYPE == MONTGOMERY_FRIENDLY { + for i := 0; i < NLEN; i++ { + top, bot := muladd(d.w[i], MConst-1, d.w[i], d.w[NLEN+i-1]) + d.w[NLEN+i-1] = bot + d.w[NLEN+i] += top + } + b := NewBIG() + + for i := 0; i < NLEN; i++ { + b.w[i] = d.w[NLEN+i] + } + b.norm() + return b + } + + if MODTYPE == GENERALISED_MERSENNE { // Ed448 only + t := d.split(MODBITS) + b := NewBIGdcopy(d) + b.add(t) + dd := NewDBIGscopy(t) + dd.shl(MODBITS / 2) + + tt := dd.split(MODBITS) + lo := NewBIGdcopy(dd) + b.add(tt) + b.add(lo) + b.norm() + tt.shl(MODBITS / 2) + b.add(tt) + + carry := b.w[NLEN-1] >> TBITS + b.w[NLEN-1] &= TMASK + b.w[0] += carry + + ix := 224 / int(BASEBITS) + b.w[ix] += carry << (224 % BASEBITS) + b.norm() + return b + } + + if MODTYPE == NOT_SPECIAL { + md := NewBIGints(Modulus) + return monty(md, MConst, d) + } + return NewBIG() +} + +// find appoximation to quotient of a/m +// Out by at most 2. +// Note that MAXXES is bounded to be 2-bits less than half a word +func quo(n *BIG, m *BIG) int { + var num Chunk + var den Chunk + hb := uint(CHUNK) / 2 + if TBITS < hb { + sh := hb - TBITS + num = (n.w[NLEN-1] << sh) | (n.w[NLEN-2] >> (BASEBITS - sh)) + den = (m.w[NLEN-1] << sh) | (m.w[NLEN-2] >> (BASEBITS - sh)) + + } else { + num = n.w[NLEN-1] + den = m.w[NLEN-1] + } + return int(num / (den + 1)) +} + +/* reduce this mod Modulus */ +func (F *FP) reduce() { + m := NewBIGints(Modulus) + r := NewBIGints(Modulus) + var sb uint + F.x.norm() + + if F.XES > 16 { + q := quo(F.x, m) + carry := r.pmul(q) + r.w[NLEN-1] += carry << BASEBITS + F.x.sub(r) + F.x.norm() + sb = 2 + } else { + sb = logb2(uint32(F.XES - 1)) + } + + m.fshl(sb) + for sb > 0 { + sr := ssn(r, F.x, m) + F.x.cmove(r, 1-sr) + sb -= 1 + } + + F.XES = 1 +} + +/* test this=0? */ +func (F *FP) iszilch() bool { + W := NewFPcopy(F) + W.reduce() + return W.x.iszilch() +} + +func (F *FP) islarger() int { + if F.iszilch() { + return 0 + } + sx := NewBIGints(Modulus) + fx := F.redc() + sx.sub(fx) + sx.norm() + return Comp(fx, sx) +} + +func (F *FP) ToBytes(b []byte) { + F.redc().ToBytes(b) +} + +func FP_fromBytes(b []byte) *FP { + t := FromBytes(b) + return NewFPbig(t) +} + +func (F *FP) isunity() bool { + W := NewFPcopy(F) + W.reduce() + return W.redc().isunity() +} + +/* copy from FP b */ +func (F *FP) copy(b *FP) { + F.x.copy(b.x) + F.XES = b.XES +} + +/* set this=0 */ +func (F *FP) zero() { + F.x.zero() + F.XES = 1 +} + +/* set this=1 */ +func (F *FP) one() { + F.x.one() + F.nres() +} + +/* return sign */ +func (F *FP) sign() int { + if BIG_ENDIAN_SIGN { + m := NewBIGints(Modulus) + m.dec(1) + m.fshr(1) + n := NewFPcopy(F) + n.reduce() + w := n.redc() + cp := Comp(w, m) + return ((cp + 1) & 2) >> 1 + } else { + W := NewFPcopy(F) + W.reduce() + return W.redc().parity() + } +} + +/* normalise this */ +func (F *FP) norm() { + F.x.norm() +} + +/* swap FPs depending on d */ +func (F *FP) cswap(b *FP, d int) { + c := int32(d) + c = ^(c - 1) + t := c & (F.XES ^ b.XES) + F.XES ^= t + b.XES ^= t + F.x.cswap(b.x, d) +} + +/* copy FPs depending on d */ +func (F *FP) cmove(b *FP, d int) { + F.x.cmove(b.x, d) + c := int32(-d) + F.XES ^= (F.XES ^ b.XES) & c +} + +/* this*=b mod Modulus */ +func (F *FP) mul(b *FP) { + + if int64(F.XES)*int64(b.XES) > int64(FEXCESS) { + F.reduce() + } + + d := mul(F.x, b.x) + F.x.copy(mod(d)) + F.XES = 2 +} + +/* this = -this mod Modulus */ +func (F *FP) neg() { + m := NewBIGints(Modulus) + sb := logb2(uint32(F.XES - 1)) + + m.fshl(sb) + F.x.rsub(m) + + F.XES = (1 << sb) + 1 + if F.XES > FEXCESS { + F.reduce() + } +} + +/* this*=c mod Modulus, where c is a small int */ +func (F *FP) imul(c int) { + // F.norm() + s := false + if c < 0 { + c = -c + s = true + } + + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + d := F.x.pxmul(c) + F.x.copy(mod(d)) + F.XES = 2 + } else { + if F.XES*int32(c) <= FEXCESS { + F.x.pmul(c) + F.XES *= int32(c) + } else { + n := NewFPint(c) + F.mul(n) + } + } + if s { + F.neg() + F.norm() + } +} + +/* this*=this mod Modulus */ +func (F *FP) sqr() { + if int64(F.XES)*int64(F.XES) > int64(FEXCESS) { + F.reduce() + } + d := sqr(F.x) + F.x.copy(mod(d)) + F.XES = 2 +} + +/* this+=b */ +func (F *FP) add(b *FP) { + F.x.add(b.x) + F.XES += b.XES + if F.XES > FEXCESS { + F.reduce() + } +} + +/* this-=b */ +func (F *FP) sub(b *FP) { + n := NewFPcopy(b) + n.neg() + F.add(n) +} + +func (F *FP) rsub(b *FP) { + F.neg() + F.add(b) +} + +/* this/=2 mod Modulus */ +func (F *FP) div2() { + p := NewBIGints(Modulus) + pr := F.x.parity() + w := NewBIGcopy(F.x) + F.x.fshr(1) + w.add(p) + w.norm() + w.fshr(1) + F.x.cmove(w, pr) +} + +/* return jacobi symbol (this/Modulus) */ +func (F *FP) jacobi() int { + w := F.redc() + p := NewBIGints(Modulus) + return w.Jacobi(p) +} + +/* return TRUE if this==a */ +func (F *FP) Equals(a *FP) bool { + f := NewFPcopy(F) + s := NewFPcopy(a) + + s.reduce() + f.reduce() + if Comp(s.x, f.x) == 0 { + return true + } + return false +} + +func (F *FP) pow(e *BIG) *FP { + var tb []*FP + var w [1 + (NLEN*int(BASEBITS)+3)/4]int8 + F.norm() + t := NewBIGcopy(e) + t.norm() + nb := 1 + (t.nbits()+3)/4 + + for i := 0; i < nb; i++ { + lsbs := t.lastbits(4) + t.dec(lsbs) + t.norm() + w[i] = int8(lsbs) + t.fshr(4) + } + tb = append(tb, NewFPint(1)) + tb = append(tb, NewFPcopy(F)) + for i := 2; i < 16; i++ { + tb = append(tb, NewFPcopy(tb[i-1])) + tb[i].mul(F) + } + r := NewFPcopy(tb[w[nb-1]]) + for i := nb - 2; i >= 0; i-- { + r.sqr() + r.sqr() + r.sqr() + r.sqr() + r.mul(tb[w[i]]) + } + r.reduce() + return r +} + +// See https://eprint.iacr.org/2018/1038 +// return this^(p-3)/4 or this^(p-5)/8 +func (F *FP) fpow() *FP { + ac := [11]int{1, 2, 3, 6, 12, 15, 30, 60, 120, 240, 255} + var xp []*FP + // phase 1 + xp = append(xp, NewFPcopy(F)) + xp = append(xp, NewFPcopy(F)) + xp[1].sqr() + xp = append(xp, NewFPcopy(xp[1])) + xp[2].mul(F) + xp = append(xp, NewFPcopy(xp[2])) + xp[3].sqr() + xp = append(xp, NewFPcopy(xp[3])) + xp[4].sqr() + xp = append(xp, NewFPcopy(xp[4])) + xp[5].mul(xp[2]) + xp = append(xp, NewFPcopy(xp[5])) + xp[6].sqr() + xp = append(xp, NewFPcopy(xp[6])) + xp[7].sqr() + xp = append(xp, NewFPcopy(xp[7])) + xp[8].sqr() + xp = append(xp, NewFPcopy(xp[8])) + xp[9].sqr() + xp = append(xp, NewFPcopy(xp[9])) + xp[10].mul(xp[5]) + var n, c int + + e := int(PM1D2) + + n = int(MODBITS) + if MODTYPE == GENERALISED_MERSENNE { // Ed448 ONLY + n /= 2 + } + + n -= (e + 1) + c = (int(MConst) + (1 << e) + 1) / (1 << (e + 1)) + + nd := 0 + for c%2 == 0 { + c /= 2 + n -= 1 + nd++ + } + + bw := 0 + w := 1 + for w < c { + w *= 2 + bw += 1 + } + k := w - c + + i := 10 + key := NewFP() + + if k != 0 { + for ac[i] > k { + i-- + } + key.copy(xp[i]) + k -= ac[i] + } + + for k != 0 { + i-- + if ac[i] > k { + continue + } + key.mul(xp[i]) + k -= ac[i] + } + // phase 2 + xp[1].copy(xp[2]) + xp[2].copy(xp[5]) + xp[3].copy(xp[10]) + + j := 3 + m := 8 + nw := n - bw + t := NewFP() + for 2*m < nw { + t.copy(xp[j]) + j++ + for i = 0; i < m; i++ { + t.sqr() + } + xp[j].copy(xp[j-1]) + xp[j].mul(t) + m *= 2 + } + lo := nw - m + r := NewFPcopy(xp[j]) + + for lo != 0 { + m /= 2 + j-- + if lo < m { + continue + } + lo -= m + t.copy(r) + for i = 0; i < m; i++ { + t.sqr() + } + r.copy(t) + r.mul(xp[j]) + } + // phase 3 + if bw != 0 { + for i = 0; i < bw; i++ { + r.sqr() + } + r.mul(key) + } + + if MODTYPE == GENERALISED_MERSENNE { // Ed448 ONLY + key.copy(r) + r.sqr() + r.mul(F) + for i = 0; i < n+1; i++ { + r.sqr() + } + r.mul(key) + } + for nd > 0 { + r.sqr() + nd-- + } + return r +} + +// calculates r=x^(p-1-2^e)/2^{e+1) where 2^e|p-1 +func (F *FP) progen() { + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + F.copy(F.fpow()) + return + } + e := uint(PM1D2) + m := NewBIGints(Modulus) + m.dec(1) + m.shr(e) + m.dec(1) + m.fshr(1) + F.copy(F.pow(m)) +} + +/* this=1/this mod Modulus */ +func (F *FP) inverse(h *FP) { + e := int(PM1D2) + F.norm() + s := NewFPcopy(F) + for i := 0; i < e-1; i++ { + s.sqr() + s.mul(F) + } + if h == nil { + F.progen() + } else { + F.copy(h) + } + for i := 0; i <= e; i++ { + F.sqr() + } + F.mul(s) + F.reduce() +} + +/* test for Quadratic residue */ +func (F *FP) qr(h *FP) int { + r := NewFPcopy(F) + e := int(PM1D2) + r.progen() + if h != nil { + h.copy(r) + } + + r.sqr() + r.mul(F) + for i := 0; i < e-1; i++ { + r.sqr() + } + + if r.isunity() { + return 1 + } else { + return 0 + } +} + +/* return sqrt(this) mod Modulus */ +func (F *FP) sqrt(h *FP) *FP { + e := int(PM1D2) + g := NewFPcopy(F) + if h == nil { + g.progen() + } else { + g.copy(h) + } + + m := NewBIGints(ROI) + v := NewFPbig(m) + + t := NewFPcopy(g) + t.sqr() + t.mul(F) + + r := NewFPcopy(F) + r.mul(g) + b := NewFPcopy(t) + + for k := e; k > 1; k-- { + for j := 1; j < k-1; j++ { + b.sqr() + } + var u int + if b.isunity() { + u = 0 + } else { + u = 1 + } + g.copy(r) + g.mul(v) + r.cmove(g, u) + v.sqr() + g.copy(t) + g.mul(v) + t.cmove(g, u) + b.copy(t) + } + sgn := r.sign() + nr := NewFPcopy(r) + nr.neg() + nr.norm() + r.cmove(nr, sgn) + return r +} + +func (F *FP) invsqrt(i *FP, s *FP) int { + h := NewFP() + qr := F.qr(h) + s.copy(F.sqrt(h)) + i.copy(F) + i.inverse(h) + return qr +} + +// Two for the price of one - See Hamburg https://eprint.iacr.org/2012/309.pdf +// Calculate inverse of i and square root of s, return QR +func FP_tpo(i *FP, s *FP) int { + w := NewFPcopy(s) + t := NewFPcopy(i) + w.mul(i) + t.mul(w) + qr := t.invsqrt(i, s) + i.mul(w) + s.mul(i) + return qr +} + +/* return sqrt(this) mod Modulus +func (F *FP) sqrt() *FP { + F.reduce() + if PM1D2 == 2 { + var v *FP + i := NewFPcopy(F) + i.x.shl(1) + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + v = i.fpow() + } else { + b := NewBIGints(Modulus) + b.dec(5) + b.norm() + b.shr(3) + v = i.pow(b) + } + + i.mul(v) + i.mul(v) + i.x.dec(1) + r := NewFPcopy(F) + r.mul(v) + r.mul(i) + r.reduce() + return r + } else { + var r *FP + if MODTYPE == PSEUDO_MERSENNE || MODTYPE == GENERALISED_MERSENNE { + r = F.fpow() + r.mul(F) + } else { + b := NewBIGints(Modulus) + b.inc(1) + b.norm() + b.shr(2) + r = F.pow(b) + } + return r + } +} */ diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/HPKE.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/HPKE.go index 5b6bf2915d9..4fa36f40be4 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/HPKE.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/HPKE.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * @@ -23,146 +25,144 @@ package FP256BN - import "github.com/hyperledger/fabric-amcl/core" func reverse(X []byte) { - lx:=len(X) - for i:=0;i>8)&3 - aead:=(config_id>>10)&3 + kem := config_id & 255 + kdf := (config_id >> 8) & 3 + aead := (config_id >> 10) & 3 txt := "HPKE" KEM := []byte(txt) var SUITE_ID []byte - for i:=0;i> 8) & 3 + aead := (config_id >> 10) & 3 + + txt := "HPKE" + KEM := []byte(txt) + var SUITE_ID []byte + for i := 0; i < len(KEM); i++ { + SUITE_ID = append(SUITE_ID, KEM[i]) + } + num := core.InttoBytes(kem, 2) + SUITE_ID = append(SUITE_ID, num[0]) + SUITE_ID = append(SUITE_ID, num[1]) + num = core.InttoBytes(kdf, 2) + SUITE_ID = append(SUITE_ID, num[0]) + SUITE_ID = append(SUITE_ID, num[1]) + num = core.InttoBytes(aead, 2) + SUITE_ID = append(SUITE_ID, num[0]) + SUITE_ID = append(SUITE_ID, num[1]) + + ar := core.InttoBytes(mode, 1) + for i := 0; i < len(ar); i++ { + context = append(context, ar[i]) + } + + H := labeledExtract(nil, SUITE_ID, "psk_id_hash", pskID) + for i := 0; i < HASH_TYPE; i++ { + context = append(context, H[i]) + } + H = labeledExtract(nil, SUITE_ID, "info_hash", info) + for i := 0; i < HASH_TYPE; i++ { + context = append(context, H[i]) + } + //H=labeledExtract(nil,SUITE_ID,"psk_hash",psk) + //secret:=labeledExtract(H,SUITE_ID,"secret",Z) + + secret := labeledExtract(Z, SUITE_ID, "secret", psk) + + key := labeledExpand(secret, SUITE_ID, "key", context, AESKEY) + nonce := labeledExpand(secret, SUITE_ID, "base_nonce", context, 12) + exp_secret := labeledExpand(secret, SUITE_ID, "exp", context, HASH_TYPE) + + return key, nonce, exp_secret +} diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/MPIN.go b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/MPIN.go index e655de70975..66a6d195a43 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/MPIN.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/FP256BN/MPIN.go @@ -1,3 +1,5 @@ +//go:build !386 && !arm + /* * Copyright (c) 2012-2020 MIRACL UK Ltd. * @@ -23,7 +25,6 @@ package FP256BN import "github.com/hyperledger/fabric-amcl/core" - const MFS int = int(MODBYTES) const MGS int = int(MODBYTES) const BAD_PARAMS int = -11 @@ -37,33 +38,33 @@ const MAXPIN int32 = 10000 /* PIN less than this */ const PBLEN int32 = 14 /* Number of bits in PIN */ func MPIN_HASH_ID(sha int, ID []byte) []byte { - return core.GPhashit(core.MC_SHA2,sha,int(MODBYTES),0,nil,-1,ID) + return core.GPhashit(core.MC_SHA2, sha, int(MODBYTES), 0, nil, -1, ID) //return mhashit(sha, 0, ID) } -func roundup(a int,b int) int { - return (((a)-1)/(b)+1) +func roundup(a int, b int) int { + return (((a)-1)/(b) + 1) } -func MPIN_ENCODE_TO_CURVE(DST []byte,ID []byte,HCID []byte) { +func MPIN_ENCODE_TO_CURVE(DST []byte, ID []byte, HCID []byte) { q := NewBIGints(Modulus) k := q.Nbits() r := NewBIGints(CURVE_Order) - m := r.Nbits(); - L:= roundup(k+roundup(m,2),8) - var fd=make([]byte,L) - OKM:=core.XMD_Expand(core.MC_SHA2,HASH_TYPE,L,DST,ID) - - for j:=0;j olen { for i := 0; i < olen%hlen; i++ { K[k] = B[i] @@ -234,7 +235,7 @@ func PBKDF2(hash int, sha int, Pass []byte, Salt []byte, rep int, olen int) []by return key } -func blksize(hash int,sha int) int { +func blksize(hash int, sha int) int { b := 0 if hash == MC_SHA2 { b = 64 @@ -243,7 +244,7 @@ func blksize(hash int,sha int) int { } } if hash == MC_SHA3 { - b=200-2*sha + b = 200 - 2*sha } return b } @@ -255,8 +256,10 @@ func HMAC(hash int, sha int, tag []byte, olen int, K []byte, M []byte) int { * The output is the calculated tag */ var B []byte - b := blksize(hash,sha) - if b == 0 {return 0} + b := blksize(hash, sha) + if b == 0 { + return 0 + } var K0 [200]byte //olen := len(tag) @@ -293,41 +296,41 @@ func HMAC(hash int, sha int, tag []byte, olen int, K []byte, M []byte) int { return 1 } -func HKDF_Extract(hash int, hlen int, SALT []byte, IKM []byte) []byte { +func HKDF_Extract(hash int, hlen int, SALT []byte, IKM []byte) []byte { var PRK []byte - for i:=0;i 0 { @@ -335,7 +338,7 @@ func HKDF_Expand(hash int, hlen int, olen int, PRK []byte, INFO []byte) []byte { T = append(T, INFO[j]) } T = append(T, byte(n+1)) - HMAC(hash,hlen,K[:],flen,PRK,T); + HMAC(hash, hlen, K[:], flen, PRK, T) for j := 0; j < flen; j++ { OKM = append(OKM, K[j]) } @@ -343,68 +346,79 @@ func HKDF_Expand(hash int, hlen int, olen int, PRK []byte, INFO []byte) []byte { return OKM } -func ceil(a int,b int) int { - return (((a)-1)/(b)+1) +func ceil(a int, b int) int { + return (((a)-1)/(b) + 1) } -func XOF_Expand(hlen int,olen int,DST []byte,MSG []byte) []byte { - var OKM =make([]byte,olen) +func XOF_Expand(hlen int, olen int, DST []byte, MSG []byte) []byte { + var OKM = make([]byte, olen) H := NewSHA3(hlen) - for i:=0;i> 8) & 0xff)); - H.Process(byte(olen & 0xff)); + H.Process(byte((olen >> 8) & 0xff)) + H.Process(byte(olen & 0xff)) - for i:=0;i> 8) & 0xff) - TMP[1]=byte(olen & 0xff) - TMP[2]=byte(0) + ell := ceil(olen, hlen) + blk := blksize(hash, hlen) + TMP[0] = byte((olen >> 8) & 0xff) + TMP[1] = byte(olen & 0xff) + TMP[2] = byte(0) - for j:=0;j=256 { + W := GPhashit(hash, hlen, 0, 0, OS, -1, DST) + R=xmd_Expand_Short_DST(hash,hlen,olen,W,MSG) + } else { + R=xmd_Expand_Short_DST(hash,hlen,olen,DST,MSG) + } + return R; +} /* Mask Generation Function */ @@ -421,7 +435,7 @@ func MGF1(sha int, Z []byte, olen int, K []byte) { cthreshold++ } for counter := 0; counter < cthreshold; counter++ { - B := GPhashit(MC_SHA2,sha,0,0,Z,int32(counter),nil) + B := GPhashit(MC_SHA2, sha, 0, 0, Z, int32(counter), nil) //B := hashit(sha, Z, counter) if k+hlen > olen { @@ -438,7 +452,6 @@ func MGF1(sha int, Z []byte, olen int, K []byte) { } } - func MGF1XOR(sha int, Z []byte, olen int, K []byte) { hlen := sha @@ -449,7 +462,7 @@ func MGF1XOR(sha int, Z []byte, olen int, K []byte) { cthreshold++ } for counter := 0; counter < cthreshold; counter++ { - B := GPhashit(MC_SHA2,sha,0,0,Z,int32(counter),nil) + B := GPhashit(MC_SHA2, sha, 0, 0, Z, int32(counter), nil) //B := hashit(sha, Z, counter) if k+hlen > olen { @@ -479,7 +492,7 @@ func RSA_PKCS15(sha int, m []byte, w []byte, RFS int) bool { if olen < idlen+hlen+10 { return false } - H := SPhashit(MC_SHA2,sha,m) + H := SPhashit(MC_SHA2, sha, m) //H := hashit(sha, m, -1) for i := 0; i < len(w); i++ { @@ -581,107 +594,107 @@ func RSA_PKCS15b(sha int, m []byte, w []byte, RFS int) bool { func RSA_PSS_ENCODE(sha int, m []byte, rng *RAND, RFS int) []byte { - emlen:=RFS - embits:=8*emlen-1 + emlen := RFS + embits := 8*emlen - 1 - hlen:=sha - SALT := make([]byte,hlen) + hlen := sha + SALT := make([]byte, hlen) for i := 0; i < hlen; i++ { SALT[i] = rng.GetByte() } - mask:=byte(0xff>>(8*emlen-embits)) + mask := byte(0xff >> (8*emlen - embits)) - H := SPhashit(MC_SHA2,sha,m) + H := SPhashit(MC_SHA2, sha, m) if emlen < hlen+hlen+2 { return nil } - MD := make([]byte,8+hlen+hlen) - for i:=0;i<8;i++ { - MD[i]=0; + MD := make([]byte, 8+hlen+hlen) + for i := 0; i < 8; i++ { + MD[i] = 0 } - for i:=0;i>(8*emlen-embits)) - - HMASK := SPhashit(MC_SHA2,sha,m) - if emlen < hlen + hlen + 2 { + emlen := len(f) + embits := 8*emlen - 1 + hlen := sha + SALT := make([]byte, hlen) + mask := byte(0xff >> (8*emlen - embits)) + + HMASK := SPhashit(MC_SHA2, sha, m) + if emlen < hlen+hlen+2 { return false } - if (f[emlen-1]!=byte(0xbc)) { + if f[emlen-1] != byte(0xbc) { return false } - if (f[0]&(^mask))!=0 { + if (f[0] & (^mask)) != 0 { return false } - DB:=make([]byte,emlen-hlen-1) - for i:=0;i= olen-seedlen-hlen { + if k >= m { return nil } if DBMASK[k] != 0 { break } } + t := DBMASK[k] */ - t := DBMASK[k] - if !comp || x != 0 || t != 0x01 { + if comp!=0 || x != 0 || t != 0x01 { for i := 0; i < olen-seedlen; i++ { DBMASK[i] = 0 } return nil } - var r = make([]byte, olen-seedlen-hlen-k-1) + var r = make([]byte, m-k-1) - for i := 0; i < olen-seedlen-hlen-k-1; i++ { + for i := 0; i < m-k-1; i++ { r[i] = DBMASK[i+k+1] } @@ -847,9 +870,6 @@ func RSA_OAEP_DECODE(sha int, p []byte, f []byte, RFS int) []byte { return r } - - - /* @@ -868,7 +888,7 @@ func main() { var ikm []byte var salt []byte var info []byte - + for i:=0;i<22;i++ {ikm=append(ikm,0x0b)} for i:=0;i<13;i++ {salt=append(salt,byte(i))} for i:=0;i<10;i++ {info=append(info,byte(0xf0+i))} @@ -884,7 +904,6 @@ func main() { for i := 0; i < len(okm); i++ { fmt.Printf("%02x", okm[i]) } - + } */ - diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/KYBER.go b/vendor/github.com/hyperledger/fabric-amcl/core/KYBER.go new file mode 100644 index 00000000000..b753cd2590d --- /dev/null +++ b/vendor/github.com/hyperledger/fabric-amcl/core/KYBER.go @@ -0,0 +1,796 @@ +/* + * Copyright (c) 2012-2020 MIRACL UK Ltd. + * + * This file is part of MIRACL Core + * (see https://github.com/miracl/core). + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Kyber API */ + +package core + + + +const KY_LGN uint = 8 +const KY_DEGREE int = (1 << KY_LGN); +const KY_PRIME int32 = 0xD01 + +const KY_ONE int32 = 0x549 // R mod Q +const KY_QINV int32 = 62209 // q^(-1) mod 2^16 + +const KYBER_SECRET_CPA_SIZE_512 int = (2*(KY_DEGREE*3)/2) +const KYBER_PUBLIC_SIZE_512 int = (32+2*(KY_DEGREE*3)/2) +const KYBER_CIPHERTEXT_SIZE_512 int = ((10*2+4)*KY_DEGREE/8) +const KYBER_SECRET_CCA_SIZE_512 int = (KYBER_SECRET_CPA_SIZE_512+KYBER_PUBLIC_SIZE_512+64) +const KYBER_SHARED_SECRET_512 int = 32 + +const KYBER_SECRET_CPA_SIZE_768 int = (3*(KY_DEGREE*3)/2) +const KYBER_PUBLIC_SIZE_768 int = (32+3*(KY_DEGREE*3)/2) +const KYBER_CIPHERTEXT_SIZE_768 int = ((10*3+4)*KY_DEGREE/8) +const KYBER_SECRET_CCA_SIZE_768 int = (KYBER_SECRET_CPA_SIZE_768+KYBER_PUBLIC_SIZE_768+64) +const KYBER_SHARED_SECRET_768 int = 32 + +const KYBER_SECRET_CPA_SIZE_1024 int = (4*(KY_DEGREE*3)/2) +const KYBER_PUBLIC_SIZE_1024 int = (32+4*(KY_DEGREE*3)/2) +const KYBER_CIPHERTEXT_SIZE_1024 int = ((11*4+5)*KY_DEGREE/8) +const KYBER_SECRET_CCA_SIZE_1024 int = (KYBER_SECRET_CPA_SIZE_1024+KYBER_PUBLIC_SIZE_1024+64) +const KYBER_SHARED_SECRET_1024 int = 32 + +const KY_MAXK = 4; + +// parameters for each security level +// K,eta1,eta2,du,dv,shared secret +var PARAMS_512 = [6]int{2,3,2,10,4,32} +var PARAMS_768 = [6]int{3,2,2,10,4,32} +var PARAMS_1024 = [6]int{4,2,2,11,5,32} + +/* Translated from public domain reference implementation code - taken from https://github.com/pq-crystals/kyber */ +var ZETAS = [256]int16{ + -1044, -758, -359, -1517, 1493, 1422, 287, 202, + -171, 622, 1577, 182, 962, -1202, -1474, 1468, + 573, -1325, 264, 383, -829, 1458, -1602, -130, + -681, 1017, 732, 608, -1542, 411, -205, -1571, + 1223, 652, -552, 1015, -1293, 1491, -282, -1544, + 516, -8, -320, -666, -1618, -1162, 126, 1469, + -853, -90, -271, 830, 107, -1421, -247, -951, + -398, 961, -1508, -725, 448, -1065, 677, -1275, + -1103, 430, 555, 843, -1251, 871, 1550, 105, + 422, 587, 177, -235, -291, -460, 1574, 1653, + -246, 778, 1159, -147, -777, 1483, -602, 1119, + -1590, 644, -872, 349, 418, 329, -156, -75, + 817, 1097, 603, 610, 1322, -1285, -1465, 384, + -1215, -136, 1218, -1335, -874, 220, -1187, -1659, + -1185, -1530, -1278, 794, -1510, -854, -870, 478, + -108, -308, 996, 991, 958, -1460, 1522, 1628} + +func montgomery_reduce(a int32) int16 { + t := int16(a*KY_QINV) + t = int16((a - int32(t)*KY_PRIME) >> 16) + return t +} + +func barrett_reduce(a int16) int16 { + v := int16(((int32(1)<<26) + KY_PRIME/2)/KY_PRIME) + vv := int32(v) + aa := int32(a) + t := int16((vv*aa + 0x2000000) >> 26); + t *= int16(KY_PRIME) + return int16(a - t); +} + +func fqmul(a int16, b int16) int16 { + return montgomery_reduce(int32(a)*int32(b)); +} + +func ntt(r []int16) { + var j int + k := 1 + for len := 128; len >= 2; len >>= 1 { + for start := 0; start < 256; start = j + len { + zeta := ZETAS[k]; k+=1 + for j = start; j < start + len; j++ { + t := fqmul(zeta, r[j + len]) + r[j + len] = r[j] - t + r[j] = r[j] + t + } + } + } +} + +func invntt(r []int16) { + var j int + f := int16(1441) // mont^2/128 + k := 127 + for len := 2; len <= 128; len <<= 1 { + for start := 0; start < 256; start = j + len { + zeta := ZETAS[k]; k-=1 + for j = start; j < start + len; j++ { + t := r[j] + r[j] = barrett_reduce(t + r[j + len]) + r[j + len] = (r[j + len] - t) + r[j + len] = fqmul(zeta, r[j + len]) + } + } + } + + for j := 0; j < 256; j++ { + r[j] = fqmul(r[j], f) + } +} + +func basemul(index int,r []int16, a []int16, b []int16,zeta int16) { + i:=index + j:=index+1 + r[i] = fqmul(a[j], b[j]) + r[i] = fqmul(r[i], zeta) + r[i] += fqmul(a[i], b[i]) + r[j] = fqmul(a[i], b[j]) + r[j] += fqmul(a[j], b[i]) +} + +func poly_reduce(r []int16) { + for i:=0;i>bt)&1) +} + +// centered binomial distribution +func cbd(bts []byte,eta int,f []int16) { + for i:=0;i>bts) + mask:=int16((1<=8{ + bts-=8 + ptr++ + } + w:=int16(r&mask) + position[0]=ptr + position[1]=bts + return w +} + +// array t has ab active bits per word +// extract bytes from array of words +// if max!=0 then -max<=t[i]<=+max +func nextbyte16(ab int,t []int16,position []int) byte { + ptr:=position[0] // index in array + bts:=position[1] // bit index in byte + + left:=ab-bts // number of bits left in this word + i:=0 + k:=ptr%256 + + w:=t[k]; w+=(w>>15)&int16(KY_PRIME) + r:=int16(w>>bts); + for left<8 { + i++ + w=t[k+i]; w+=(w>>15)&int16(KY_PRIME) + r|=w<=ab { + bts-=ab; + ptr++; + } + position[0]=ptr + position[1]=bts + return byte(r&0xff); +} + +// encode polynomial vector of length len with coefficients of length L, into packed bytes +func encode(t []int16,pos []int,L int,pack []byte,pptr int) { + k:=(KY_DEGREE*L)/8 // compressed length + for n:=0;n>15)&int16(KY_PRIME) + t[i]= int16(((twod*int32(t[i])+KY_PRIME/2)/KY_PRIME)&(twod-1)) + } +} + +// decompress polynomial coefficents in place, for polynomial vector of length len +func decompress(t []int16,d int) { + twod1:=int32(1<<(d-1)) + for i:=0;i>d) + } +} + +// input entropy, output key pair +func cpa_keypair(params [6]int,tau []byte,sk []byte,pk []byte) { + sh := NewSHA3(SHA3_HASH512) + var rho [32]byte + var sigma [33]byte + var buff [256]byte + + ck:=params[0] + var r [KY_DEGREE]int16 + var w [KY_DEGREE]int16 + var Aij [KY_DEGREE]int16 + + var s= make([][KY_DEGREE]int16, ck) + var e= make([][KY_DEGREE]int16, ck) + var p= make([][KY_DEGREE]int16, ck) + + eta1:=params[1] + public_key_size:=32+ck*(KY_DEGREE*3)/2 +// secret_cpa_key_size:=ck*(KY_DEGREE*3)/2 + + for i:=0;i<32;i++ { + sh.Process(tau[i]) + } + bf := sh.Hash(); + for i:=0;i<32;i++ { + rho[i]=bf[i] + sigma[i]=bf[i+32] + } + sigma[32]=0 // N + +// create s + for i:=0;i> 31) - return (x + mask) ^ mask -} - -/* Montgomery stuff */ - -func redc(T uint64) int32 { - m := (uint32(T) * NHS_ND) - return int32((uint64(m)*uint64(NHS_PRIME) + T) >> NHS_WL) -} - -func nres(x int32) int32 { - return redc(uint64(x) * NHS_R2MODP) -} - -func modmul(a int32, b int32) int32 { - return redc(uint64(a) * uint64(b)) -} - -/* NTT code */ -/* Cooley-Tukey NTT */ - -func ntt(x []int32) { - t := NHS_DEGREE / 2 - q := NHS_PRIME - - /* Convert to Montgomery form */ - for j := 0; j < NHS_DEGREE; j++ { - x[j] = nres(x[j]) - } - m := 1 - for m < NHS_DEGREE { - k := 0 - for i := 0; i < m; i++ { - S := NHS_roots[m+i] - for j := k; j < k+t; j++ { - U := x[j] - V := modmul(x[j+t], S) - x[j] = U + V - x[j+t] = U + 2*q - V - } - k += 2 * t - } - t /= 2 - m *= 2 - } -} - -/* Gentleman-Sande INTT */ - -func intt(x []int32) { - t := 1 - q := NHS_PRIME - - m := NHS_DEGREE / 2 - for m > 1 { - k := 0 - for i := 0; i < m; i++ { - S := NHS_iroots[m+i] - for j := k; j < k+t; j++ { - U := x[j] - V := x[j+t] - x[j] = U + V - W := U + int32(NHS_DEGREE)*q - V - x[j+t] = modmul(W, S) - } - k += 2 * t - } - t *= 2 - m /= 2 - } - - /* Last iteration merged with n^-1 */ - - t = NHS_DEGREE / 2 - for j := 0; j < t; j++ { - U := x[j] - V := x[j+t] - W := U + int32(NHS_DEGREE)*q - V - x[j+t] = modmul(W, NHS_invpr) - x[j] = modmul(U+V, NHS_inv) - } - /* convert back from Montgomery to "normal" form */ - for j := 0; j < NHS_DEGREE; j++ { - x[j] = redc(uint64(x[j])) - x[j] -= q - x[j] += (x[j] >> (NHS_WL - 1)) & q - } -} - -/* See https://eprint.iacr.org/2016/1157.pdf */ - -func encode(key []byte, poly []int32) { - - q2 := NHS_PRIME / 2 - j := 0 - for i := 0; i < 256; { - kj := key[j] - j++ - for k := 0; k < 8; k++ { - b := int32(kj & 1) - poly[i] = b * q2 - poly[i+256] = b * q2 - poly[i+512] = b * q2 - poly[i+768] = b * q2 - kj >>= 1 - i++ - } - } -} - -func decode(poly []int32, key []byte) { - q2 := NHS_PRIME / 2 - for i := 0; i < 32; i++ { - key[i] = 0 - } - - j := 0 - for i := 0; i < 256; { - for k := 0; k < 8; k++ { - t := nabs(poly[i]-q2) + nabs(poly[i+256]-q2) + nabs(poly[i+512]-q2) + nabs(poly[i+768]-q2) - b := t - NHS_PRIME - b = (b >> 31) & 1 - key[j] = (key[j] >> 1) + byte(b<<7) - i++ - } - j++ - } -} - -/* convert 32-byte seed to random polynomial */ - -func parse(seed []byte, poly []int32) { - var hash [4 * NHS_DEGREE]byte - sh := NewSHA3(SHA3_SHAKE128) - - for i := 0; i < 32; i++ { - sh.Process(seed[i]) - } - sh.Shake(hash[:], 4*NHS_DEGREE) - - j := 0 - for i := 0; i < NHS_DEGREE; i++ { - n := int32(hash[j] & 0x7f) - n <<= 8 - n += int32(hash[j+1]) - n <<= 8 - n += int32(hash[j+2]) - n <<= 8 - n += int32(hash[j+3]) - j += 4 - poly[i] = nres(n) - //poly[i]=modmul(n,NHS_ONE) // reduce 31-bit random number mod q - } -} - -/* Compress 14 bits polynomial coefficients into byte array */ -/* 7 bytes is 3x14 */ - -func nhs_pack(poly []int32, array []byte) { - j := 0 - for i := 0; i < NHS_DEGREE; { - a := poly[i] - b := poly[i+1] - c := poly[i+2] - d := poly[i+3] - i += 4 - array[j] = byte(a & 0xff) - array[j+1] = byte(((a >> 8) | (b << 6)) & 0xff) - array[j+2] = byte((b >> 2) & 0xff) - array[j+3] = byte(((b >> 10) | (c << 4)) & 0xff) - array[j+4] = byte((c >> 4) & 0xff) - array[j+5] = byte(((c >> 12) | (d << 2)) & 0xff) - array[j+6] = byte(d >> 6) - j += 7 - } -} - -func nhs_unpack(array []byte, poly []int32) { - j := 0 - for i := 0; i < NHS_DEGREE; { - a := int32((array[j]) & 0xff) - b := int32((array[j+1]) & 0xff) - c := int32((array[j+2]) & 0xff) - d := int32((array[j+3]) & 0xff) - e := int32((array[j+4]) & 0xff) - f := int32((array[j+5]) & 0xff) - g := int32((array[j+6]) & 0xff) - j += 7 - poly[i] = a | ((b & 0x3f) << 8) - poly[i+1] = (b >> 6) | (c << 2) | ((d & 0xf) << 10) - poly[i+2] = (d >> 4) | (e << 4) | ((f & 3) << 12) - poly[i+3] = (f >> 2) | (g << 6) - i += 4 - } -} - -/* See https://eprint.iacr.org/2016/1157.pdf */ - -func compress(poly []int32, array []byte) { - - var col int32 = 0 - j := 0 - for i := 0; i < NHS_DEGREE; { - for k := 0; k < 8; k++ { - b := round((poly[i]*8), NHS_PRIME) & 7 - col = (col << 3) + b - i += 1 - } - array[j] = byte(col & 0xff) - array[j+1] = byte((col >> 8) & 0xff) - array[j+2] = byte((col >> 16) & 0xff) - j += 3 - col = 0 - } -} - -func decompress(array []byte, poly []int32) { - var col int32 = 0 - j := 0 - for i := 0; i < NHS_DEGREE; { - col = int32(array[j+2]) & 0xff - col = (col << 8) + (int32(array[j+1]) & 0xff) - col = (col << 8) + (int32(array[j]) & 0xff) - j += 3 - for k := 0; k < 8; k++ { - b := (col & 0xe00000) >> 21 - col <<= 3 - poly[i] = round((b * NHS_PRIME), 8) - i += 1 - } - } -} - -/* generate centered binomial distribution */ - -func error(rng *RAND, poly []int32) { - var r int32 - for i := 0; i < NHS_DEGREE; i++ { - n1 := (int32(rng.GetByte()) & 0xff) + ((int32(rng.GetByte()) & 0xff) << 8) - n2 := (int32(rng.GetByte()) & 0xff) + ((int32(rng.GetByte()) & 0xff) << 8) - r = 0 - for j := 0; j < 16; j++ { - r += (n1 & 1) - (n2 & 1) - n1 >>= 1 - n2 >>= 1 - } - poly[i] = (r + NHS_PRIME) - } -} - -func redc_it(p []int32) { - for i := 0; i < NHS_DEGREE; i++ { - p[i] = redc(uint64(p[i])) - } -} - -func nres_it(p []int32) { - for i := 0; i < NHS_DEGREE; i++ { - p[i] = nres(p[i]) - } -} - -func poly_mul(p1 []int32, p2 []int32, p3 []int32) { - for i := 0; i < NHS_DEGREE; i++ { - p1[i] = modmul(p2[i], p3[i]) - } -} - -func poly_add(p1 []int32, p2 []int32, p3 []int32) { - for i := 0; i < NHS_DEGREE; i++ { - p1[i] = (p2[i] + p3[i]) - } -} - -func poly_sub(p1 []int32, p2 []int32, p3 []int32) { - for i := 0; i < NHS_DEGREE; i++ { - p1[i] = (p2[i] + NHS_PRIME - p3[i]) - } -} - -/* reduces inputs < 2q */ -func poly_soft_reduce(poly []int32) { - for i := 0; i < NHS_DEGREE; i++ { - e := poly[i] - NHS_PRIME - poly[i] = e + ((e >> (NHS_WL - 1)) & NHS_PRIME) - } -} - -/* fully reduces modulo q */ -func poly_hard_reduce(poly []int32) { - for i := 0; i < NHS_DEGREE; i++ { - e := modmul(poly[i], NHS_ONE) - e = e - NHS_PRIME - poly[i] = e + ((e >> (NHS_WL - 1)) & NHS_PRIME) - } -} - -/* API files */ - -func NHS_SERVER_1(rng *RAND, SB []byte, S []byte) { - var seed [32]byte - var array [1792]byte - var s [NHS_DEGREE]int32 - var e [NHS_DEGREE]int32 - var b [NHS_DEGREE]int32 - - for i := 0; i < 32; i++ { - seed[i] = rng.GetByte() - } - - parse(seed[:], b[:]) - - error(rng, e[:]) - error(rng, s[:]) - - ntt(s[:]) - ntt(e[:]) - poly_mul(b[:], b[:], s[:]) - poly_add(b[:], b[:], e[:]) - poly_hard_reduce(b[:]) - - redc_it(b[:]) - nhs_pack(b[:], array[:]) - - for i := 0; i < 32; i++ { - SB[i] = seed[i] - } - - for i := 0; i < 1792; i++ { - SB[i+32] = array[i] - } - - poly_hard_reduce(s[:]) - nhs_pack(s[:], array[:]) - - for i := 0; i < 1792; i++ { - S[i] = array[i] - } - -} - -func NHS_CLIENT(rng *RAND, SB []byte, UC []byte, KEY []byte) { - sh := NewSHA3(SHA3_HASH256) - var seed [32]byte - var array [1792]byte - var key [32]byte - var cc [384]byte - - var sd [NHS_DEGREE]int32 - var ed [NHS_DEGREE]int32 - var u [NHS_DEGREE]int32 - var k [NHS_DEGREE]int32 - var c [NHS_DEGREE]int32 - - error(rng, sd[:]) - error(rng, ed[:]) - - ntt(sd[:]) - ntt(ed[:]) - - for i := 0; i < 32; i++ { - seed[i] = SB[i] - } - - for i := 0; i < 1792; i++ { - array[i] = SB[i+32] - } - - parse(seed[:], u[:]) - - poly_mul(u[:], u[:], sd[:]) - poly_add(u[:], u[:], ed[:]) - poly_hard_reduce(u[:]) - - for i := 0; i < 32; i++ { - key[i] = rng.GetByte() - } - - for i := 0; i < 32; i++ { - sh.Process(key[i]) - } - hkey := sh.Hash() - - encode(hkey[:], k[:]) - - nhs_unpack(array[:], c[:]) - nres_it(c[:]) - - poly_mul(c[:], c[:], sd[:]) - intt(c[:]) - error(rng, ed[:]) - poly_add(c[:], c[:], ed[:]) - poly_add(c[:], c[:], k[:]) - - compress(c[:], cc[:]) - - sh.Init(SHA3_HASH256) - for i := 0; i < 32; i++ { - sh.Process(hkey[i]) - } - fkey := sh.Hash() - - for i := 0; i < 32; i++ { - KEY[i] = fkey[i] - } - - redc_it(u[:]) - nhs_pack(u[:], array[:]) - - for i := 0; i < 1792; i++ { - UC[i] = array[i] - } - - for i := 0; i < 384; i++ { - UC[i+1792] = cc[i] - } -} - -func NHS_SERVER_2(S []byte, UC []byte, KEY []byte) { - sh := NewSHA3(SHA3_HASH256) - - var c [NHS_DEGREE]int32 - var s [NHS_DEGREE]int32 - var k [NHS_DEGREE]int32 - - var array [1792]byte - var key [32]byte - var cc [384]byte - - for i := 0; i < 1792; i++ { - array[i] = UC[i] - } - - nhs_unpack(array[:], k[:]) - nres_it(k[:]) - - for i := 0; i < 384; i++ { - cc[i] = UC[i+1792] - } - - decompress(cc[:], c[:]) - - for i := 0; i < 1792; i++ { - array[i] = S[i] - } - - nhs_unpack(array[:], s[:]) - - poly_mul(k[:], k[:], s[:]) - intt(k[:]) - poly_sub(k[:], c[:], k[:]) - poly_soft_reduce(k[:]) - - decode(k[:], key[:]) - - for i := 0; i < 32; i++ { - sh.Process(key[i]) - } - hkey := sh.Hash() - - for i := 0; i < 32; i++ { - KEY[i] = hkey[i] - } -} - -/* -func main() { - - srng:=NewRAND() - var sraw [100]byte - for i:=0;i<100;i++ {sraw[i]=byte(i+1)} - srng.Seed(100,sraw[:]) - - crng:=NewRAND() - var craw [100]byte - for i:=0;i<100;i++ {craw[i]=byte(i+2)} - crng.Seed(100,craw[:]) - - var S [1792] byte - - var SB [1824] byte - NHS_SERVER_1(srng,SB[:],S[:]) - var UC [2176] byte - var KEYB [32] byte - NHS_CLIENT(crng,SB[:],UC[:],KEYB[:]) - - fmt.Printf("Bob's Key= ") - for i:=0;i<32;i++ { - fmt.Printf("%02x", KEYB[i]) - } - fmt.Printf("\n") - var KEYA [32] byte - NHS_SERVER_2(S[:],UC[:],KEYA[:]) - - fmt.Printf("Alice Key= ") - for i:=0;i<32;i++ { - fmt.Printf("%02x", KEYA[i]) - } - -} -*/ diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/RAND.go b/vendor/github.com/hyperledger/fabric-amcl/core/RAND.go index 842e605fd08..c4ac3a33d4e 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/RAND.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/RAND.go @@ -30,7 +30,7 @@ package core -//import "fmt" + const rand_NK int = 21 const rand_NJ int = 6 diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/SHA3.go b/vendor/github.com/hyperledger/fabric-amcl/core/SHA3.go index 3402caaaf31..d1e0a8fdf16 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/SHA3.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/SHA3.go @@ -30,7 +30,7 @@ package core -//import "fmt" + const SHA3_HASH224 int = 28 const SHA3_HASH256 int = 32 @@ -152,9 +152,9 @@ func NewSHA3copy(HC *SHA3) *SHA3 { H.s[i][j] = HC.s[i][j] } } - H.length=HC.length - H.len=HC.len - H.rate=HC.rate + H.length = HC.length + H.len = HC.len + H.rate = HC.rate return H } @@ -187,7 +187,6 @@ func (H *SHA3) Process_num(n int32) { H.Process(byte(n & 0xff)) } - /* squeeze the sponge */ func (H *SHA3) Squeeze(buff []byte, olen int) { // olen:=len(buff) @@ -225,7 +224,7 @@ func (H *SHA3) Squeeze(buff []byte, olen int) { } /* Generate Hash */ -func (H *SHA3) Hash() []byte { /* generate a SHA3 hash of appropriate size */ +func (H *SHA3) Hash() []byte { /* generate a SHA3 hash of appropriate size */ var digest [64]byte q := H.rate - int(H.length%uint64(H.rate)) if q == 1 { @@ -241,7 +240,7 @@ func (H *SHA3) Hash() []byte { /* generate a SHA3 hash of appropriate size */ return digest[0:H.len] } -func (H *SHA3) Continuing_Hash() [] byte { +func (H *SHA3) Continuing_Hash() []byte { sh := NewSHA3copy(H) return sh.Hash() } @@ -262,7 +261,7 @@ func (H *SHA3) Shake(hash []byte, olen int) { /* generate a SHA3 hash of appropr func (H *SHA3) Continuing_Shake(hash []byte, olen int) { sh := NewSHA3copy(H) - sh.Shake(hash,olen) + sh.Shake(hash, olen) } /* test program: should produce digest */ diff --git a/vendor/github.com/hyperledger/fabric-amcl/core/SHARE.go b/vendor/github.com/hyperledger/fabric-amcl/core/SHARE.go index be569a4134d..9785490239e 100644 --- a/vendor/github.com/hyperledger/fabric-amcl/core/SHARE.go +++ b/vendor/github.com/hyperledger/fabric-amcl/core/SHARE.go @@ -62,13 +62,13 @@ var ltab = [...]byte{ 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7} type SHARE struct { - ID byte // Unique Share ID - NSR byte // Number of Shares required for recovery - B []byte // Share + ID byte // Unique Share ID + NSR byte // Number of Shares required for recovery + B []byte // Share } func add(x byte, y byte) byte { - return (x^y) + return (x ^ y) } func mul(x byte, y byte) byte { /* x.y= AntiLog(Log(x) + Log(y)) */ @@ -92,15 +92,15 @@ func inv(x byte) byte { /* Lagrange interpolation */ func interpolate(n int, x []byte, y []byte) byte { - yp:=byte(0) - for i:=0;i=256 || nsr<2 || nsr>=256 { - S.ID=0 - S.NSR=0 - S.B=nil + if id < 1 || id >= 256 || nsr < 2 || nsr >= 256 { + S.ID = 0 + S.NSR = 0 + S.B = nil return S } - S.ID=byte(id) - S.NSR=byte(nsr) - m:=len(M) - S.B=make([]byte,m) + S.ID = byte(id) + S.NSR = byte(nsr) + m := len(M) + S.B = make([]byte, m) rng := NewRAND() rng.Clean() - rng.Seed(len(R),R) - for j:=0;j= fpByteSize { + l = fpByteSize + } + padded := make([]byte, fpByteSize) + copy(padded[fpByteSize-l:], in[:]) + var a int + for i := 0; i < fpNumberOfLimbs; i++ { + a = fpByteSize - i*8 + fe[i] = uint64(padded[a-1]) | uint64(padded[a-2])<<8 | + uint64(padded[a-3])<<16 | uint64(padded[a-4])<<24 | + uint64(padded[a-5])<<32 | uint64(padded[a-6])<<40 | + uint64(padded[a-7])<<48 | uint64(padded[a-8])<<56 + } + return fe +} + +func (fe *fe) setBig(a *big.Int) *fe { + return fe.setBytes(a.Bytes()) +} + +func (fe *fe) setString(s string) (*fe, error) { + if s[:2] == "0x" { + s = s[2:] + } + bytes, err := hex.DecodeString(s) + if err != nil { + return nil, err + } + return fe.setBytes(bytes), nil +} + +func (fe *fe) set(fe2 *fe) *fe { + fe[0] = fe2[0] + fe[1] = fe2[1] + fe[2] = fe2[2] + fe[3] = fe2[3] + fe[4] = fe2[4] + fe[5] = fe2[5] + return fe +} + +func (fe *fe) bytes() []byte { + out := make([]byte, fpByteSize) + var a int + for i := 0; i < fpNumberOfLimbs; i++ { + a = fpByteSize - i*8 + out[a-1] = byte(fe[i]) + out[a-2] = byte(fe[i] >> 8) + out[a-3] = byte(fe[i] >> 16) + out[a-4] = byte(fe[i] >> 24) + out[a-5] = byte(fe[i] >> 32) + out[a-6] = byte(fe[i] >> 40) + out[a-7] = byte(fe[i] >> 48) + out[a-8] = byte(fe[i] >> 56) + } + return out +} + +func (fe *fe) big() *big.Int { + return new(big.Int).SetBytes(fe.bytes()) +} + +func (fe *fe) string() (s string) { + for i := fpNumberOfLimbs - 1; i >= 0; i-- { + s = fmt.Sprintf("%s%16.16x", s, fe[i]) + } + return "0x" + s +} + +func (fe *fe) zero() *fe { + fe[0] = 0 + fe[1] = 0 + fe[2] = 0 + fe[3] = 0 + fe[4] = 0 + fe[5] = 0 + return fe +} + +func (fe *fe) one() *fe { + return fe.set(r1) +} + +func (fe *fe) rand(r io.Reader) (*fe, error) { + bi, err := rand.Int(r, modulus.big()) + if err != nil { + return nil, err + } + return fe.setBig(bi), nil +} + +func (fe *fe) isValid() bool { + return fe.cmp(&modulus) == -1 +} + +func (fe *fe) isOdd() bool { + var mask uint64 = 1 + return fe[0]&mask != 0 +} + +func (fe *fe) isEven() bool { + var mask uint64 = 1 + return fe[0]&mask == 0 +} + +func (fe *fe) isZero() bool { + return (fe[5] | fe[4] | fe[3] | fe[2] | fe[1] | fe[0]) == 0 +} + +func (fe *fe) isOne() bool { + return fe.equal(r1) +} + +func (fe *fe) cmp(fe2 *fe) int { + for i := fpNumberOfLimbs - 1; i >= 0; i-- { + if fe[i] > fe2[i] { + return 1 + } else if fe[i] < fe2[i] { + return -1 + } + } + return 0 +} + +func (fe *fe) equal(fe2 *fe) bool { + return fe2[0] == fe[0] && fe2[1] == fe[1] && fe2[2] == fe[2] && fe2[3] == fe[3] && fe2[4] == fe[4] && fe2[5] == fe[5] +} + +func (e *fe) signBE() bool { + negZ, z := new(fe), new(fe) + fromMont(z, e) + neg(negZ, z) + return negZ.cmp(z) > -1 +} + +func (e *fe) sign() bool { + r := new(fe) + fromMont(r, e) + return r[0]&1 == 0 +} + +func (e *fe) div2(u uint64) { + e[0] = e[0]>>1 | e[1]<<63 + e[1] = e[1]>>1 | e[2]<<63 + e[2] = e[2]>>1 | e[3]<<63 + e[3] = e[3]>>1 | e[4]<<63 + e[4] = e[4]>>1 | e[5]<<63 + e[5] = e[5]>>1 | u<<63 +} + +func (e *fe) mul2() uint64 { + u := e[5] >> 63 + e[5] = e[5]<<1 | e[4]>>63 + e[4] = e[4]<<1 | e[3]>>63 + e[3] = e[3]<<1 | e[2]>>63 + e[2] = e[2]<<1 | e[1]>>63 + e[1] = e[1]<<1 | e[0]>>63 + e[0] = e[0] << 1 + return u +} + +func (e *fe2) zero() *fe2 { + e[0].zero() + e[1].zero() + return e +} + +func (e *fe2) one() *fe2 { + e[0].one() + e[1].zero() + return e +} + +func (e *fe2) set(e2 *fe2) *fe2 { + e[0].set(&e2[0]) + e[1].set(&e2[1]) + return e +} + +func (e *fe2) rand(r io.Reader) (*fe2, error) { + a0, err := new(fe).rand(r) + if err != nil { + return nil, err + } + a1, err := new(fe).rand(r) + if err != nil { + return nil, err + } + return &fe2{*a0, *a1}, nil +} + +func (e *fe2) isOne() bool { + return e[0].isOne() && e[1].isZero() +} + +func (e *fe2) isZero() bool { + return e[0].isZero() && e[1].isZero() +} + +func (e *fe2) equal(e2 *fe2) bool { + return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) +} + +func (e *fe2) signBE() bool { + if !e[1].isZero() { + return e[1].signBE() + } + return e[0].signBE() +} + +func (e *fe2) sign() bool { + r := new(fe) + if !e[0].isZero() { + fromMont(r, &e[0]) + return r[0]&1 == 0 + } + fromMont(r, &e[1]) + return r[0]&1 == 0 +} + +func (e *fe6) zero() *fe6 { + e[0].zero() + e[1].zero() + e[2].zero() + return e +} + +func (e *fe6) one() *fe6 { + e[0].one() + e[1].zero() + e[2].zero() + return e +} + +func (e *fe6) set(e2 *fe6) *fe6 { + e[0].set(&e2[0]) + e[1].set(&e2[1]) + e[2].set(&e2[2]) + return e +} + +func (e *fe6) rand(r io.Reader) (*fe6, error) { + a0, err := new(fe2).rand(r) + if err != nil { + return nil, err + } + a1, err := new(fe2).rand(r) + if err != nil { + return nil, err + } + a2, err := new(fe2).rand(r) + if err != nil { + return nil, err + } + return &fe6{*a0, *a1, *a2}, nil +} + +func (e *fe6) isOne() bool { + return e[0].isOne() && e[1].isZero() && e[2].isZero() +} + +func (e *fe6) isZero() bool { + return e[0].isZero() && e[1].isZero() && e[2].isZero() +} + +func (e *fe6) equal(e2 *fe6) bool { + return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) && e[2].equal(&e2[2]) +} + +func (e *fe12) zero() *fe12 { + e[0].zero() + e[1].zero() + return e +} + +func (e *fe12) one() *fe12 { + e[0].one() + e[1].zero() + return e +} + +func (e *fe12) set(e2 *fe12) *fe12 { + e[0].set(&e2[0]) + e[1].set(&e2[1]) + return e +} + +func (e *fe12) rand(r io.Reader) (*fe12, error) { + a0, err := new(fe6).rand(r) + if err != nil { + return nil, err + } + a1, err := new(fe6).rand(r) + if err != nil { + return nil, err + } + return &fe12{*a0, *a1}, nil +} + +func (e *fe12) isOne() bool { + return e[0].isOne() && e[1].isZero() +} + +func (e *fe12) isZero() bool { + return e[0].isZero() && e[1].isZero() +} + +func (e *fe12) equal(e2 *fe12) bool { + return e[0].equal(&e2[0]) && e[1].equal(&e2[1]) +} diff --git a/vendor/github.com/kilic/bls12-381/fp.go b/vendor/github.com/kilic/bls12-381/fp.go new file mode 100644 index 00000000000..83396a5bb86 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/fp.go @@ -0,0 +1,350 @@ +package bls12381 + +import ( + "errors" + "math/big" +) + +func fromBytes(in []byte) (*fe, error) { + fe := &fe{} + if len(in) != fpByteSize { + return nil, errors.New("input string must be equal 48 bytes") + } + fe.setBytes(in) + if !fe.isValid() { + return nil, errors.New("must be less than modulus") + } + toMont(fe, fe) + return fe, nil +} + +func from64Bytes(in []byte) (*fe, error) { + if len(in) != 32*2 { + return nil, errors.New("input string must be equal 64 bytes") + } + a0 := make([]byte, fpByteSize) + copy(a0[fpByteSize-32:fpByteSize], in[:32]) + a1 := make([]byte, fpByteSize) + copy(a1[fpByteSize-32:fpByteSize], in[32:]) + e0, err := fromBytes(a0) + if err != nil { + return nil, err + } + e1, err := fromBytes(a1) + if err != nil { + return nil, err + } + // F = 2 ^ 256 * R + F := fe{ + 0x75b3cd7c5ce820f, + 0x3ec6ba621c3edb0b, + 0x168a13d82bff6bce, + 0x87663c4bf8c449d2, + 0x15f34c83ddc8d830, + 0xf9628b49caa2e85, + } + + mul(e0, e0, &F) + add(e1, e1, e0) + return e1, nil +} + +func fromBig(in *big.Int) (*fe, error) { + fe := new(fe).setBig(in) + if !fe.isValid() { + return nil, errors.New("invalid input string") + } + toMont(fe, fe) + return fe, nil +} + +func fromString(in string) (*fe, error) { + fe, err := new(fe).setString(in) + if err != nil { + return nil, err + } + if !fe.isValid() { + return nil, errors.New("invalid input string") + } + toMont(fe, fe) + return fe, nil +} + +func toBytes(e *fe) []byte { + e2 := new(fe) + fromMont(e2, e) + return e2.bytes() +} + +func toBig(e *fe) *big.Int { + e2 := new(fe) + fromMont(e2, e) + return e2.big() +} + +func toString(e *fe) (s string) { + e2 := new(fe) + fromMont(e2, e) + return e2.string() +} + +func toMont(c, a *fe) { + mul(c, a, r2) +} + +func fromMont(c, a *fe) { + mul(c, a, &fe{1}) +} + +func exp(c, a *fe, e *big.Int) { + z := new(fe).set(r1) + for i := e.BitLen(); i >= 0; i-- { + mul(z, z, z) + if e.Bit(i) == 1 { + mul(z, z, a) + } + } + c.set(z) +} + +func inverse(inv, e *fe) { + if e.isZero() { + inv.zero() + return + } + u := new(fe).set(&modulus) + v := new(fe).set(e) + s := &fe{1} + r := &fe{0} + var k int + var z uint64 + var found = false + // Phase 1 + for i := 0; i < sixWordBitSize*2; i++ { + if v.isZero() { + found = true + break + } + if u.isEven() { + u.div2(0) + s.mul2() + } else if v.isEven() { + v.div2(0) + z += r.mul2() + } else if u.cmp(v) == 1 { + lsubAssign(u, v) + u.div2(0) + laddAssign(r, s) + s.mul2() + } else { + lsubAssign(v, u) + v.div2(0) + laddAssign(s, r) + z += r.mul2() + } + k += 1 + } + + if !found { + inv.zero() + return + } + + if k < fpBitSize || k > fpBitSize+sixWordBitSize { + inv.zero() + return + } + + if r.cmp(&modulus) != -1 || z > 0 { + lsubAssign(r, &modulus) + } + u.set(&modulus) + lsubAssign(u, r) + + // Phase 2 + for i := k; i < 2*sixWordBitSize; i++ { + double(u, u) + } + inv.set(u) +} + +func inverseBatch(in []fe) { + + n, N, setFirst := 0, len(in), false + + for i := 0; i < len(in); i++ { + if !in[i].isZero() { + n++ + } + } + if n == 0 { + return + } + + tA := make([]fe, n) + tB := make([]fe, n) + + for i, j := 0, 0; i < N; i++ { + if !in[i].isZero() { + if !setFirst { + setFirst = true + tA[j].set(&in[i]) + } else { + mul(&tA[j], &in[i], &tA[j-1]) + } + j = j + 1 + } + } + + inverse(&tB[n-1], &tA[n-1]) + for i, j := N-1, n-1; j != 0; i-- { + if !in[i].isZero() { + mul(&tB[j-1], &tB[j], &in[i]) + j = j - 1 + } + } + + for i, j := 0, 0; i < N; i++ { + if !in[i].isZero() { + if setFirst { + setFirst = false + in[i].set(&tB[j]) + } else { + mul(&in[i], &tA[j-1], &tB[j]) + } + j = j + 1 + } + } +} + +func rsqrt(c, a *fe) bool { + t0, t1 := new(fe), new(fe) + sqrtAddchain(t0, a) + mul(t1, t0, a) + square(t1, t1) + ret := t1.equal(a) + c.set(t0) + return ret +} + +func sqrt(c, a *fe) bool { + u, v := new(fe).set(a), new(fe) + // a ^ (p - 3) / 4 + sqrtAddchain(c, a) + // a ^ (p + 1) / 4 + mul(c, c, u) + + square(v, c) + return u.equal(v) +} + +func _sqrt(c, a *fe) bool { + u, v := new(fe).set(a), new(fe) + exp(c, a, pPlus1Over4) + square(v, c) + return u.equal(v) +} + +func sqrtAddchain(c, a *fe) { + chain := func(c *fe, n int, a *fe) { + for i := 0; i < n; i++ { + square(c, c) + } + mul(c, c, a) + } + + t := make([]fe, 16) + t[13].set(a) + square(&t[0], &t[13]) + mul(&t[8], &t[0], &t[13]) + square(&t[4], &t[0]) + mul(&t[1], &t[8], &t[0]) + mul(&t[6], &t[4], &t[8]) + mul(&t[9], &t[1], &t[4]) + mul(&t[12], &t[6], &t[4]) + mul(&t[3], &t[9], &t[4]) + mul(&t[7], &t[12], &t[4]) + mul(&t[15], &t[3], &t[4]) + mul(&t[10], &t[7], &t[4]) + mul(&t[2], &t[15], &t[4]) + mul(&t[11], &t[10], &t[4]) + square(&t[0], &t[3]) + mul(&t[14], &t[11], &t[4]) + mul(&t[5], &t[0], &t[8]) + mul(&t[4], &t[0], &t[1]) + + chain(&t[0], 12, &t[15]) + chain(&t[0], 7, &t[7]) + chain(&t[0], 4, &t[1]) + chain(&t[0], 6, &t[6]) + chain(&t[0], 7, &t[11]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 2, &t[8]) + chain(&t[0], 6, &t[3]) + chain(&t[0], 6, &t[3]) + chain(&t[0], 6, &t[9]) + chain(&t[0], 3, &t[8]) + chain(&t[0], 7, &t[3]) + chain(&t[0], 4, &t[3]) + chain(&t[0], 6, &t[7]) + chain(&t[0], 6, &t[14]) + chain(&t[0], 3, &t[13]) + chain(&t[0], 8, &t[3]) + chain(&t[0], 7, &t[11]) + chain(&t[0], 5, &t[12]) + chain(&t[0], 6, &t[3]) + chain(&t[0], 6, &t[5]) + chain(&t[0], 4, &t[9]) + chain(&t[0], 8, &t[5]) + chain(&t[0], 4, &t[3]) + chain(&t[0], 7, &t[11]) + chain(&t[0], 9, &t[10]) + chain(&t[0], 2, &t[8]) + chain(&t[0], 5, &t[6]) + chain(&t[0], 7, &t[1]) + chain(&t[0], 7, &t[9]) + chain(&t[0], 6, &t[11]) + chain(&t[0], 5, &t[5]) + chain(&t[0], 5, &t[10]) + chain(&t[0], 5, &t[10]) + chain(&t[0], 8, &t[3]) + chain(&t[0], 7, &t[2]) + chain(&t[0], 9, &t[7]) + chain(&t[0], 5, &t[3]) + chain(&t[0], 3, &t[8]) + chain(&t[0], 8, &t[7]) + chain(&t[0], 3, &t[8]) + chain(&t[0], 7, &t[9]) + chain(&t[0], 9, &t[7]) + chain(&t[0], 6, &t[2]) + chain(&t[0], 6, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 4, &t[3]) + chain(&t[0], 3, &t[8]) + chain(&t[0], 8, &t[2]) + chain(&t[0], 7, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 4, &t[7]) + chain(&t[0], 4, &t[6]) + chain(&t[0], 7, &t[4]) + chain(&t[0], 5, &t[5]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 5, &t[4]) + chain(&t[0], 4, &t[3]) + chain(&t[0], 6, &t[2]) + chain(&t[0], 4, &t[1]) + square(c, &t[0]) +} + +func isQuadraticNonResidue(a *fe) bool { + if a.isZero() { + return true + } + return !sqrt(new(fe), a) +} diff --git a/vendor/github.com/kilic/bls12-381/fp12.go b/vendor/github.com/kilic/bls12-381/fp12.go new file mode 100644 index 00000000000..49445b729b8 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/fp12.go @@ -0,0 +1,287 @@ +package bls12381 + +import ( + "errors" + "math/big" +) + +type fp12 struct { + fp12temp + fp6 *fp6 +} + +type fp12temp struct { + t2 [9]*fe2 + t6 [5]*fe6 + t12 *fe12 +} + +func newFp12Temp() fp12temp { + t2 := [9]*fe2{} + t6 := [5]*fe6{} + for i := 0; i < len(t2); i++ { + t2[i] = &fe2{} + } + for i := 0; i < len(t6); i++ { + t6[i] = &fe6{} + } + return fp12temp{t2, t6, &fe12{}} +} + +func newFp12(fp6 *fp6) *fp12 { + t := newFp12Temp() + if fp6 == nil { + return &fp12{t, newFp6(nil)} + } + return &fp12{t, fp6} +} + +func (e *fp12) fp2() *fp2 { + return e.fp6.fp2 +} + +func (e *fp12) fromBytes(in []byte) (*fe12, error) { + if len(in) != 576 { + return nil, errors.New("input string length must be equal to 576 bytes") + } + fp6 := e.fp6 + c1, err := fp6.fromBytes(in[:6*fpByteSize]) + if err != nil { + return nil, err + } + c0, err := fp6.fromBytes(in[6*fpByteSize:]) + if err != nil { + return nil, err + } + return &fe12{*c0, *c1}, nil +} + +func (e *fp12) toBytes(a *fe12) []byte { + fp6 := e.fp6 + out := make([]byte, 12*fpByteSize) + copy(out[:6*fpByteSize], fp6.toBytes(&a[1])) + copy(out[6*fpByteSize:], fp6.toBytes(&a[0])) + return out +} + +func (e *fp12) new() *fe12 { + return new(fe12) +} + +func (e *fp12) zero() *fe12 { + return new(fe12) +} + +func (e *fp12) one() *fe12 { + return new(fe12).one() +} + +func (e *fp12) add(c, a, b *fe12) { + fp6 := e.fp6 + // c0 = a0 + b0 + // c1 = a1 + b1 + fp6.add(&c[0], &a[0], &b[0]) + fp6.add(&c[1], &a[1], &b[1]) + +} + +func (e *fp12) double(c, a *fe12) { + fp6 := e.fp6 + // c0 = 2a0 + // c1 = 2a1 + fp6.double(&c[0], &a[0]) + fp6.double(&c[1], &a[1]) +} + +func (e *fp12) sub(c, a, b *fe12) { + fp6 := e.fp6 + // c0 = a0 - b0 + // c1 = a1 - b1s + fp6.sub(&c[0], &a[0], &b[0]) + fp6.sub(&c[1], &a[1], &b[1]) + +} + +func (e *fp12) neg(c, a *fe12) { + fp6 := e.fp6 + // c0 = -a0 + // c1 = -a1 + fp6.neg(&c[0], &a[0]) + fp6.neg(&c[1], &a[1]) +} + +func (e *fp12) conjugate(c, a *fe12) { + fp6 := e.fp6 + // c0 = a0 + // c1 = -a1 + c[0].set(&a[0]) + fp6.neg(&c[1], &a[1]) +} + +func (e *fp12) square(c, a *fe12) { + fp6, t := e.fp6, e.t6 + // Multiplication and Squaring on Pairing-Friendly Fields + // Complex squaring algorithm + // https://eprint.iacr.org/2006/471 + + fp6.add(t[0], &a[0], &a[1]) // a0 + a1 + fp6.mul(t[2], &a[0], &a[1]) // v0 = a0a1 + fp6.mulByNonResidue(t[1], &a[1]) // βa1 + fp6.addAssign(t[1], &a[0]) // a0 + βa1 + fp6.mulByNonResidue(t[3], t[2]) // βa0a1 + fp6.mulAssign(t[0], t[1]) // (a0 + a1)(a0 + βa1) + fp6.subAssign(t[0], t[2]) // (a0 + a1)(a0 + βa1) - v0 + fp6.sub(&c[0], t[0], t[3]) // c0 = (a0 + a1)(a0 + βa1) - v0 - βa0a1 + fp6.double(&c[1], t[2]) // c1 = 2v0 +} + +func (e *fp12) cyclotomicSquare(c, a *fe12) { + t, fp2 := e.t2, e.fp2() + // Guide to Pairing Based Cryptography + // 5.5.4 Airthmetic in Cyclotomic Groups + + e.fp4Square(t[3], t[4], &a[0][0], &a[1][1]) + fp2.sub(t[2], t[3], &a[0][0]) + fp2.doubleAssign(t[2]) + fp2.add(&c[0][0], t[2], t[3]) + fp2.add(t[2], t[4], &a[1][1]) + fp2.doubleAssign(t[2]) + fp2.add(&c[1][1], t[2], t[4]) + e.fp4Square(t[3], t[4], &a[1][0], &a[0][2]) + e.fp4Square(t[5], t[6], &a[0][1], &a[1][2]) + fp2.sub(t[2], t[3], &a[0][1]) + fp2.doubleAssign(t[2]) + fp2.add(&c[0][1], t[2], t[3]) + fp2.add(t[2], t[4], &a[1][2]) + fp2.doubleAssign(t[2]) + fp2.add(&c[1][2], t[2], t[4]) + fp2.mulByNonResidue(t[3], t[6]) + fp2.add(t[2], t[3], &a[1][0]) + fp2.doubleAssign(t[2]) + fp2.add(&c[1][0], t[2], t[3]) + fp2.sub(t[2], t[5], &a[0][2]) + fp2.doubleAssign(t[2]) + fp2.add(&c[0][2], t[2], t[5]) +} + +func (e *fp12) mul(c, a, b *fe12) { + t, fp6 := e.t6, e.fp6 + // Guide to Pairing Based Cryptography + // Algorithm 5.16 + + fp6.mul(t[1], &a[0], &b[0]) // v0 = a0b0 + fp6.mul(t[2], &a[1], &b[1]) // v1 = a1b1 + fp6.add(t[0], &a[0], &a[1]) // a0 + a1 + fp6.add(t[3], &b[0], &b[1]) // b0 + b1 + fp6.mulAssign(t[0], t[3]) // (a0 + a1)(b0 + b1) + fp6.subAssign(t[0], t[1]) // (a0 + a1)(b0 + b1) - v0 + fp6.sub(&c[1], t[0], t[2]) // c1 = (a0 + a1)(b0 + b1) - v0 - v1 + fp6.mulByNonResidue(t[2], t[2]) // βv1 + fp6.add(&c[0], t[1], t[2]) // c0 = v0 + βv1 +} + +func (e *fp12) mulAssign(a, b *fe12) { + t, fp6 := e.t6, e.fp6 + fp6.mul(t[1], &a[0], &b[0]) // v0 = a0b0 + fp6.mul(t[2], &a[1], &b[1]) // v1 = a1b1 + fp6.add(t[0], &a[0], &a[1]) // a0 + a1 + fp6.add(t[3], &b[0], &b[1]) // b0 + b1 + fp6.mulAssign(t[0], t[3]) // (a0 + a1)(b0 + b1) + fp6.subAssign(t[0], t[1]) // (a0 + a1)(b0 + b1) - v0 + fp6.sub(&a[1], t[0], t[2]) // c1 = (a0 + a1)(b0 + b1) - v0 - v1 + fp6.mulByNonResidue(t[2], t[2]) // βv1 + fp6.add(&a[0], t[1], t[2]) // c0 = v0 + βv1 +} + +func (e *fp12) fp4Square(c0, c1, a0, a1 *fe2) { + t, fp2 := e.t2, e.fp2() + // Multiplication and Squaring on Pairing-Friendly Fields + // Karatsuba squaring algorithm + // https://eprint.iacr.org/2006/471 + + fp2.square(t[0], a0) // a0^2 + fp2.square(t[1], a1) // a1^2 + fp2.mulByNonResidue(t[2], t[1]) // βa1^2 + fp2.add(c0, t[2], t[0]) // c0 = βa1^2 + a0^2 + fp2.add(t[2], a0, a1) // a0 + a1 + fp2.squareAssign(t[2]) // (a0 + a1)^2 + fp2.subAssign(t[2], t[0]) // (a0 + a1)^2 - a0^2 + fp2.sub(c1, t[2], t[1]) // (a0 + a1)^2 - a0^2 - a1^2 +} + +func (e *fp12) inverse(c, a *fe12) { + // Guide to Pairing Based Cryptography + // Algorithm 5.16 + + fp6, t := e.fp6, e.t6 + fp6.square(t[0], &a[0]) // a0^2 + fp6.square(t[1], &a[1]) // a1^2 + fp6.mulByNonResidue(t[1], t[1]) // βa1^2 + fp6.subAssign(t[0], t[1]) // v = (a0^2 - a1^2) + fp6.inverse(t[1], t[0]) // v = v^-1 + fp6.mul(&c[0], &a[0], t[1]) // c0 = a0v + fp6.mulAssign(t[1], &a[1]) // + fp6.neg(&c[1], t[1]) // c1 = -a1v +} + +func (e *fp12) mul014(a *fe12, b0, b1, b4 *fe2) { + fp2, fp6, t, u := e.fp2(), e.fp6, e.t6, e.t2[0] + fp6.mul01(t[0], &a[0], b0, b1) // t0 = a0b0 + fp6.mul1(t[1], &a[1], b4) // t1 = a1b1 + fp2.add(u, b1, b4) // u = b01 + b10 + fp6.add(t[2], &a[1], &a[0]) // a0 + a1 + fp6.mul01(t[2], t[2], b0, u) // v1 = u(a0 + a1s) + fp6.subAssign(t[2], t[0]) // v1 - t0 + fp6.sub(&a[1], t[2], t[1]) // c1 = v1 - t0 - t1 + fp6.mulByNonResidue(t[1], t[1]) // βt1 + fp6.add(&a[0], t[1], t[0]) // c0 = t0 + βt1 +} + +func (e *fp12) exp(c, a *fe12, s *big.Int) { + z := e.one() + for i := s.BitLen() - 1; i >= 0; i-- { + e.square(z, z) + if s.Bit(i) == 1 { + e.mul(z, z, a) + } + } + c.set(z) +} + +func (e *fp12) cyclotomicExp(c, a *fe12, s *big.Int) { + z := e.one() + for i := s.BitLen() - 1; i >= 0; i-- { + e.cyclotomicSquare(z, z) + if s.Bit(i) == 1 { + e.mul(z, z, a) + } + } + c.set(z) +} + +func (e *fp12) frobeniusMap1(a *fe12) { + fp6, fp2 := e.fp6, e.fp6.fp2 + fp6.frobeniusMap1(&a[0]) + fp6.frobeniusMap1(&a[1]) + fp2.mulAssign(&a[1][0], &frobeniusCoeffs12[1]) + fp2.mulAssign(&a[1][1], &frobeniusCoeffs12[1]) + fp2.mulAssign(&a[1][2], &frobeniusCoeffs12[1]) +} + +func (e *fp12) frobeniusMap2(a *fe12) { + fp6, fp2 := e.fp6, e.fp6.fp2 + fp6.frobeniusMap2(&a[0]) + fp6.frobeniusMap2(&a[1]) + fp2.mulAssign(&a[1][0], &frobeniusCoeffs12[2]) + fp2.mulAssign(&a[1][1], &frobeniusCoeffs12[2]) + fp2.mulAssign(&a[1][2], &frobeniusCoeffs12[2]) +} + +func (e *fp12) frobeniusMap3(a *fe12) { + fp6, fp2 := e.fp6, e.fp6.fp2 + fp6.frobeniusMap3(&a[0]) + fp6.frobeniusMap3(&a[1]) + fp2.mulAssign(&a[1][0], &frobeniusCoeffs12[3]) + fp2.mulAssign(&a[1][1], &frobeniusCoeffs12[3]) + fp2.mulAssign(&a[1][2], &frobeniusCoeffs12[3]) +} diff --git a/vendor/github.com/kilic/bls12-381/fp2.go b/vendor/github.com/kilic/bls12-381/fp2.go new file mode 100644 index 00000000000..077edceafaa --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/fp2.go @@ -0,0 +1,393 @@ +package bls12381 + +import ( + "errors" + "math/big" +) + +type fp2Temp struct { + t [4]*fe +} + +type fp2 struct { + fp2Temp +} + +func newFp2Temp() fp2Temp { + t := [4]*fe{} + for i := 0; i < len(t); i++ { + t[i] = &fe{} + } + return fp2Temp{t} +} + +func newFp2() *fp2 { + t := newFp2Temp() + return &fp2{t} +} + +func (e *fp2) fromBytes(in []byte) (*fe2, error) { + if len(in) != 2*fpByteSize { + return nil, errors.New("input string must be equal to 96 bytes") + } + c1, err := fromBytes(in[:fpByteSize]) + if err != nil { + return nil, err + } + c0, err := fromBytes(in[fpByteSize:]) + if err != nil { + return nil, err + } + return &fe2{*c0, *c1}, nil +} + +func (e *fp2) toBytes(a *fe2) []byte { + out := make([]byte, 2*fpByteSize) + copy(out[:fpByteSize], toBytes(&a[1])) + copy(out[fpByteSize:], toBytes(&a[0])) + return out +} + +func (e *fp2) new() *fe2 { + return new(fe2).zero() +} + +func (e *fp2) zero() *fe2 { + return new(fe2).zero() +} + +func (e *fp2) one() *fe2 { + return new(fe2).one() +} + +func (e *fp2) fromMont(c, a *fe2) { + // c0 = a0 / r + // c1 = a1 / r + fromMont(&c[0], &a[0]) + fromMont(&c[1], &a[1]) +} + +func (e *fp2) add(c, a, b *fe2) { + // c0 = a0 + b0 + // c1 = a1 + b1 + add(&c[0], &a[0], &b[0]) + add(&c[1], &a[1], &b[1]) +} + +func (e *fp2) addAssign(a, b *fe2) { + // a0 = a0 + b0 + // a1 = a1 + b1 + addAssign(&a[0], &b[0]) + addAssign(&a[1], &b[1]) +} + +func (e *fp2) ladd(c, a, b *fe2) { + // c0 = a0 + b0 + // c1 = a1 + b1 + ladd(&c[0], &a[0], &b[0]) + ladd(&c[1], &a[1], &b[1]) +} + +func (e *fp2) double(c, a *fe2) { + // c0 = 2a0 + // c1 = 2a1 + double(&c[0], &a[0]) + double(&c[1], &a[1]) +} + +func (e *fp2) doubleAssign(a *fe2) { + // a0 = 2a0 + // a1 = 2a1 + doubleAssign(&a[0]) + doubleAssign(&a[1]) +} + +func (e *fp2) ldouble(c, a *fe2) { + // c0 = 2a0 + // c1 = 2a1 + ldouble(&c[0], &a[0]) + ldouble(&c[1], &a[1]) +} + +func (e *fp2) sub(c, a, b *fe2) { + // c0 = a0 - b0 + // c1 = a1 - b1 + sub(&c[0], &a[0], &b[0]) + sub(&c[1], &a[1], &b[1]) +} + +func (e *fp2) subAssign(c, a *fe2) { + // a0 = a0 - b0 + // a1 = a1 - b1 + subAssign(&c[0], &a[0]) + subAssign(&c[1], &a[1]) +} + +func (e *fp2) neg(c, a *fe2) { + // c0 = -a0 + // c1 = -a1 + neg(&c[0], &a[0]) + neg(&c[1], &a[1]) +} + +func (e *fp2) conjugate(c, a *fe2) { + // c0 = a0 + // c1 = -a1 + c[0].set(&a[0]) + neg(&c[1], &a[1]) +} + +func (e *fp2) mul(c, a, b *fe2) { + t := e.t + // Guide to Pairing Based Cryptography + // Algorithm 5.16 + + mul(t[1], &a[0], &b[0]) // a0b0 + mul(t[2], &a[1], &b[1]) // a1b1 + ladd(t[0], &a[0], &a[1]) // a0 + a1 + ladd(t[3], &b[0], &b[1]) // b0 + b1 + sub(&c[0], t[1], t[2]) // c0 = a0b0 - a1b1 + addAssign(t[1], t[2]) // a0b0 + a1b1 + mul(t[0], t[0], t[3]) // (a0 + a1)(b0 + b1) + sub(&c[1], t[0], t[1]) // c1 = (a0 + a1)(b0 + b1) - (a0b0 + a1b1) +} + +func (e *fp2) mulAssign(a, b *fe2) { + t := e.t + mul(t[1], &a[0], &b[0]) + mul(t[2], &a[1], &b[1]) + ladd(t[0], &a[0], &a[1]) + ladd(t[3], &b[0], &b[1]) + sub(&a[0], t[1], t[2]) + addAssign(t[1], t[2]) + mul(t[0], t[0], t[3]) + sub(&a[1], t[0], t[1]) +} + +func (e *fp2) square(c, a *fe2) { + t := e.t + // Guide to Pairing Based Cryptography + // Algorithm 5.16 + + ladd(t[0], &a[0], &a[1]) // (a0 + a1) + sub(t[1], &a[0], &a[1]) // (a0 - a1) + ldouble(t[2], &a[0]) // 2a0 + mul(&c[0], t[0], t[1]) // c0 = (a0 + a1)(a0 - a1) + mul(&c[1], t[2], &a[1]) // c1 = 2a0a1 +} + +func (e *fp2) squareAssign(a *fe2) { + t := e.t + ladd(t[0], &a[0], &a[1]) + sub(t[1], &a[0], &a[1]) + ldouble(t[2], &a[0]) + mul(&a[0], t[0], t[1]) + mul(&a[1], t[2], &a[1]) +} + +func (e *fp2) mul0(c, a *fe2, b *fe) { + mul(&c[0], &a[0], b) + mul(&c[1], &a[1], b) +} + +func (e *fp2) mulByNonResidue(c, a *fe2) { + t := e.t + // c0 = (a0 - a1) + // c1 = (a0 + a1) + sub(t[0], &a[0], &a[1]) + add(&c[1], &a[0], &a[1]) + c[0].set(t[0]) +} + +func (e *fp2) mulByB(c, a *fe2) { + t := e.t + // c0 = 4a0 - 4a1 + // c1 = 4a0 + 4a1 + double(t[0], &a[0]) + doubleAssign(t[0]) + double(t[1], &a[1]) + doubleAssign(t[1]) + sub(&c[0], t[0], t[1]) + add(&c[1], t[0], t[1]) +} + +func (e *fp2) inverse(c, a *fe2) { + t := e.t + // Guide to Pairing Based Cryptography + // Algorithm 5.16 + + square(t[0], &a[0]) // a0^2 + square(t[1], &a[1]) // a1^2 + addAssign(t[0], t[1]) // a0^2 + a1^2 + inverse(t[0], t[0]) // (a0^2 + a1^2)^-1 + mul(&c[0], &a[0], t[0]) // c0 = a0(a0^2 + a1^2)^-1 + mul(t[0], t[0], &a[1]) // a1(a0^2 + a1^2)^-1 + neg(&c[1], t[0]) // c1 = a1(a0^2 + a1^2)^-1 +} + +func (e *fp2) inverseBatch(in []fe2) { + + n, N, setFirst := 0, len(in), false + + for i := 0; i < len(in); i++ { + if !in[i].isZero() { + n++ + } + } + if n == 0 { + return + } + + tA := make([]fe2, n) + tB := make([]fe2, n) + + // a, ab, abc, abcd, ... + for i, j := 0, 0; i < N; i++ { + if !in[i].isZero() { + if !setFirst { + setFirst = true + tA[j].set(&in[i]) + } else { + e.mul(&tA[j], &in[i], &tA[j-1]) + } + j = j + 1 + } + } + + // (abcd...)^-1 + e.inverse(&tB[n-1], &tA[n-1]) + + // a^-1, ab^-1, abc^-1, abcd^-1, ... + for i, j := N-1, n-1; j != 0; i-- { + if !in[i].isZero() { + e.mul(&tB[j-1], &tB[j], &in[i]) + j = j - 1 + } + } + + // a^-1, b^-1, c^-1, d^-1 + for i, j := 0, 0; i < N; i++ { + if !in[i].isZero() { + if setFirst { + setFirst = false + in[i].set(&tB[j]) + } else { + e.mul(&in[i], &tA[j-1], &tB[j]) + } + j = j + 1 + } + } +} + +func (e *fp2) exp(c, a *fe2, s *big.Int) { + z := e.one() + for i := s.BitLen() - 1; i >= 0; i-- { + e.square(z, z) + if s.Bit(i) == 1 { + e.mul(z, z, a) + } + } + c.set(z) +} + +func (e *fp2) frobeniusMap1(a *fe2) { + e.conjugate(a, a) +} + +func (e *fp2) frobeniusMap(a *fe2, power int) { + if power&1 == 1 { + e.conjugate(a, a) + } +} + +func (e *fp2) sqrt(c, a *fe2) bool { + u, x0, a1, alpha := &fe2{}, &fe2{}, &fe2{}, &fe2{} + u.set(a) + e.exp(a1, a, pMinus3Over4) + e.square(alpha, a1) + e.mul(alpha, alpha, a) + e.mul(x0, a1, a) + if alpha.equal(negativeOne2) { + neg(&c[0], &x0[1]) + c[1].set(&x0[0]) + return true + } + e.add(alpha, alpha, e.one()) + e.exp(alpha, alpha, pMinus1Over2) + e.mul(c, alpha, x0) + e.square(alpha, c) + return alpha.equal(u) +} + +func (e *fp2) isQuadraticNonResidue(a *fe2) bool { + c0, c1 := new(fe), new(fe) + square(c0, &a[0]) + square(c1, &a[1]) + add(c1, c1, c0) + return isQuadraticNonResidue(c1) +} + +// faster square root algorith is adapted from blst library +// https://github.com/supranational/blst/blob/master/src/sqrt.c + +func (e *fp2) sqrtBLST(out, inp *fe2) bool { + aa, bb := new(fe), new(fe) + ret := new(fe2) + square(aa, &inp[0]) + square(bb, &inp[1]) + add(aa, aa, bb) + sqrt(aa, aa) + sub(bb, &inp[0], aa) + add(aa, &inp[0], aa) + if aa.isZero() { + aa.set(bb) + } + mul(aa, aa, twoInv) + rsqrt(&ret[0], aa) + ret[1].set(&inp[1]) + mul(&ret[1], &ret[1], twoInv) + mul(&ret[1], &ret[1], &ret[0]) + mul(&ret[0], &ret[0], aa) + return e.sqrtAlignBLST(out, ret, ret, inp) +} + +func (e *fp2) sqrtAlignBLST(out, ret, sqrt, inp *fe2) bool { + + t0, t1 := new(fe2), new(fe2) + coeff := e.one() + e.square(t0, sqrt) + + // + e.sub(t1, t0, inp) + isSqrt := t1.isZero() + + // + e.add(t1, t0, inp) + flag := t1.isZero() + if flag { + coeff.set(sqrtMinus1) + } + isSqrt = flag || isSqrt + + // + sub(&t1[0], &t0[0], &inp[1]) + add(&t1[1], &t0[1], &inp[0]) + flag = t1.isZero() + if flag { + coeff.set(sqrtSqrtMinus1) + } + isSqrt = flag || isSqrt + + // + add(&t1[0], &t0[0], &inp[1]) + sub(&t1[1], &t0[1], &inp[0]) + flag = t1.isZero() + if flag { + + coeff.set(sqrtMinusSqrtMinus1) + } + isSqrt = flag || isSqrt + + e.mul(out, coeff, ret) + return isSqrt +} diff --git a/vendor/github.com/kilic/bls12-381/fp6.go b/vendor/github.com/kilic/bls12-381/fp6.go new file mode 100644 index 00000000000..e4648375ec8 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/fp6.go @@ -0,0 +1,364 @@ +package bls12381 + +import ( + "errors" + "math/big" +) + +type fp6Temp struct { + t [6]*fe2 +} + +type fp6 struct { + fp2 *fp2 + fp6Temp +} + +func newFp6Temp() fp6Temp { + t := [6]*fe2{} + for i := 0; i < len(t); i++ { + t[i] = &fe2{} + } + return fp6Temp{t} +} + +func newFp6(f *fp2) *fp6 { + t := newFp6Temp() + if f == nil { + return &fp6{newFp2(), t} + } + return &fp6{f, t} +} + +func (e *fp6) fromBytes(b []byte) (*fe6, error) { + if len(b) != 288 { + return nil, errors.New("input string length must be equal to 288 bytes") + } + fp2 := e.fp2 + u2, err := fp2.fromBytes(b[:2*fpByteSize]) + if err != nil { + return nil, err + } + u1, err := fp2.fromBytes(b[2*fpByteSize : 4*fpByteSize]) + if err != nil { + return nil, err + } + u0, err := fp2.fromBytes(b[4*fpByteSize:]) + if err != nil { + return nil, err + } + return &fe6{*u0, *u1, *u2}, nil +} + +func (e *fp6) toBytes(a *fe6) []byte { + fp2 := e.fp2 + out := make([]byte, 6*fpByteSize) + copy(out[:2*fpByteSize], fp2.toBytes(&a[2])) + copy(out[2*fpByteSize:4*fpByteSize], fp2.toBytes(&a[1])) + copy(out[4*fpByteSize:], fp2.toBytes(&a[0])) + return out +} + +func (e *fp6) new() *fe6 { + return new(fe6) +} + +func (e *fp6) zero() *fe6 { + return new(fe6) +} + +func (e *fp6) one() *fe6 { + return new(fe6).one() +} + +func (e *fp6) add(c, a, b *fe6) { + fp2 := e.fp2 + // c0 = a0 + b0 + // c1 = a1 + b1 + // c2 = a2 + b2 + fp2.add(&c[0], &a[0], &b[0]) + fp2.add(&c[1], &a[1], &b[1]) + fp2.add(&c[2], &a[2], &b[2]) +} + +func (e *fp6) addAssign(a, b *fe6) { + fp2 := e.fp2 + // a0 = a0 + b0 + // a1 = a1 + b1 + // a2 = a2 + b2 + fp2.addAssign(&a[0], &b[0]) + fp2.addAssign(&a[1], &b[1]) + fp2.addAssign(&a[2], &b[2]) +} + +func (e *fp6) double(c, a *fe6) { + fp2 := e.fp2 + // c0 = 2a0 + // c1 = 2a1 + // c2 = 2a2 + fp2.double(&c[0], &a[0]) + fp2.double(&c[1], &a[1]) + fp2.double(&c[2], &a[2]) +} + +func (e *fp6) doubleAssign(a *fe6) { + fp2 := e.fp2 + // c0 = 2c0 + // c1 = 2c1 + // c2 = 2c2 + fp2.doubleAssign(&a[0]) + fp2.doubleAssign(&a[1]) + fp2.doubleAssign(&a[2]) +} + +func (e *fp6) sub(c, a, b *fe6) { + fp2 := e.fp2 + // c0 = a0 - b0 + // c1 = a1 - b1 + // c2 = a2 - b2 + fp2.sub(&c[0], &a[0], &b[0]) + fp2.sub(&c[1], &a[1], &b[1]) + fp2.sub(&c[2], &a[2], &b[2]) +} + +func (e *fp6) subAssign(a, b *fe6) { + fp2 := e.fp2 + // a0 = a0 - b0 + // a1 = a1 - b1 + // a2 = a2 - b2 + fp2.subAssign(&a[0], &b[0]) + fp2.subAssign(&a[1], &b[1]) + fp2.subAssign(&a[2], &b[2]) +} + +func (e *fp6) neg(c, a *fe6) { + fp2 := e.fp2 + // c0 = -a0 + // c1 = -a1 + // c2 = -a2 + fp2.neg(&c[0], &a[0]) + fp2.neg(&c[1], &a[1]) + fp2.neg(&c[2], &a[2]) +} + +func (e *fp6) conjugate(c, a *fe6) { + fp2 := e.fp2 + // c0 = a0 + // c1 = -a1 + // c2 = a2 + c[0].set(&a[0]) + fp2.neg(&c[1], &a[1]) + c[0].set(&a[2]) +} + +func (e *fp6) mul(c, a, b *fe6) { + fp2, t := e.fp2, e.t + // Guide to Pairing Based Cryptography + // Algorithm 5.21 + + fp2.mul(t[0], &a[0], &b[0]) // v0 = a0b0 + fp2.mul(t[1], &a[1], &b[1]) // v1 = a1b1 + fp2.mul(t[2], &a[2], &b[2]) // v2 = a2b2 + fp2.add(t[3], &a[1], &a[2]) // a1 + a2 + fp2.add(t[4], &b[1], &b[2]) // b1 + b2 + fp2.mulAssign(t[3], t[4]) // (a1 + a2)(b1 + b2) + fp2.add(t[4], t[1], t[2]) // v1 + v2 + fp2.subAssign(t[3], t[4]) // (a1 + a2)(b1 + b2) - v1 - v2 + fp2.mulByNonResidue(t[3], t[3]) // ((a1 + a2)(b1 + b2) - v1 - v2)β + fp2.addAssign(t[3], t[0]) // c0 = ((a1 + a2)(b1 + b2) - v1 - v2)β + v0 + fp2.add(t[5], &a[0], &a[1]) // a0 + a1 + fp2.add(t[4], &b[0], &b[1]) // b0 + b1 + fp2.mulAssign(t[5], t[4]) // (a0 + a1)(b0 + b1) + fp2.add(t[4], t[0], t[1]) // v0 + v1 + fp2.subAssign(t[5], t[4]) // (a0 + a1)(b0 + b1) - v0 - v1 + fp2.mulByNonResidue(t[4], t[2]) // βv2 + fp2.add(&c[1], t[5], t[4]) // c1 = (a0 + a1)(b0 + b1) - v0 - v1 + βv2 + fp2.add(t[5], &a[0], &a[2]) // a0 + a2 + fp2.add(t[4], &b[0], &b[2]) // b0 + b2 + fp2.mulAssign(t[5], t[4]) // (a0 + a2)(b0 + b2) + fp2.add(t[4], t[0], t[2]) // v0 + v2 + fp2.subAssign(t[5], t[4]) // (a0 + a2)(b0 + b2) - v0 - v2 + fp2.add(&c[2], t[1], t[5]) // c2 = (a0 + a2)(b0 + b2) - v0 - v2 + v1 + c[0].set(t[3]) +} + +func (e *fp6) mulAssign(a, b *fe6) { + fp2, t := e.fp2, e.t + fp2.mul(t[0], &a[0], &b[0]) + fp2.mul(t[1], &a[1], &b[1]) + fp2.mul(t[2], &a[2], &b[2]) + fp2.add(t[3], &a[1], &a[2]) + fp2.add(t[4], &b[1], &b[2]) + fp2.mulAssign(t[3], t[4]) + fp2.add(t[4], t[1], t[2]) + fp2.subAssign(t[3], t[4]) + fp2.mulByNonResidue(t[3], t[3]) + fp2.addAssign(t[3], t[0]) + fp2.add(t[5], &a[0], &a[1]) + fp2.add(t[4], &b[0], &b[1]) + fp2.mulAssign(t[5], t[4]) + fp2.add(t[4], t[0], t[1]) + fp2.subAssign(t[5], t[4]) + fp2.mulByNonResidue(t[4], t[2]) + fp2.add(&a[1], t[5], t[4]) + fp2.add(t[5], &a[0], &a[2]) + fp2.add(t[4], &b[0], &b[2]) + fp2.mulAssign(t[5], t[4]) + fp2.add(t[4], t[0], t[2]) + fp2.subAssign(t[5], t[4]) + fp2.add(&a[2], t[1], t[5]) + a[0].set(t[3]) +} + +func (e *fp6) square(c, a *fe6) { + fp2, t := e.fp2, e.t + // Multiplication and Squaring on Pairing-Friendly Fields + // Algorithm CH-SQR2 + // https://eprint.iacr.org/2006/471 + + fp2.square(t[0], &a[0]) // s0 = a0^2 + fp2.mul(t[1], &a[0], &a[1]) // a0a1 + fp2.doubleAssign(t[1]) // s1 = 2a0a1 + fp2.sub(t[2], &a[0], &a[1]) // a0 - a1 + fp2.addAssign(t[2], &a[2]) // a0 - a1 + a2 + fp2.squareAssign(t[2]) // s2 = (a0 - a1 + a2)^2 + fp2.mul(t[3], &a[1], &a[2]) // a1a2 + fp2.doubleAssign(t[3]) // s3 = 2a1a2 + fp2.square(t[4], &a[2]) // s4 = a2^2 + fp2.mulByNonResidue(t[5], t[3]) // βs3 + fp2.add(&c[0], t[0], t[5]) // c0 = s0 + βs3 + fp2.mulByNonResidue(t[5], t[4]) // βs4 + fp2.add(&c[1], t[1], t[5]) // c1 = s1 + βs4 + fp2.addAssign(t[1], t[2]) + fp2.addAssign(t[1], t[3]) + fp2.addAssign(t[0], t[4]) + fp2.sub(&c[2], t[1], t[0]) // c2 = s1 + s2 - s0 - s4 +} + +func (e *fp6) mul01(c, a *fe6, b0, b1 *fe2) { + fp2, t := e.fp2, e.t + // v0 = a0b0 + // v1 = a1b1 + // c0 = (b1(a1 + a2) - v1)β + v0 + // c1 = (a0 + a1)(b0 + b1) - v0 - v1 + // c2 = b0(a0 + a2) - v0 + v1 + + fp2.mul(t[0], &a[0], b0) // v0 = b0a0 + fp2.mul(t[1], &a[1], b1) // v1 = a1b1 + fp2.add(t[2], &a[1], &a[2]) // a1 + a2 + fp2.mulAssign(t[2], b1) // b1(a1 + a2) + fp2.subAssign(t[2], t[1]) // b1(a1 + a2) - v1 + fp2.mulByNonResidue(t[2], t[2]) // (b1(a1 + a2) - v1)β + fp2.add(t[3], &a[0], &a[2]) // a0 + a2 + fp2.mulAssign(t[3], b0) // b0(a0 + a2) + fp2.subAssign(t[3], t[0]) // b0(a0 + a2) - v0 + fp2.add(&c[2], t[3], t[1]) // b0(a0 + a2) - v0 + v1 + fp2.add(t[4], b0, b1) // (b0 + b1) + fp2.add(t[3], &a[0], &a[1]) // (a0 + a1) + fp2.mulAssign(t[4], t[3]) // (a0 + a1)(b0 + b1) + fp2.subAssign(t[4], t[0]) // (a0 + a1)(b0 + b1) - v0 + fp2.sub(&c[1], t[4], t[1]) // (a0 + a1)(b0 + b1) - v0 - v1 + fp2.add(&c[0], t[2], t[0]) // (b1(a1 + a2) - v1)β + v0 +} + +func (e *fp6) mul1(c, a *fe6, b1 *fe2) { + fp2, t := e.fp2, e.t + // c0 = βa2b1 + // c1 = a0b1 + // c2 = a1b1 + fp2.mul(t[0], &a[2], b1) + fp2.mul(&c[2], &a[1], b1) + fp2.mul(&c[1], &a[0], b1) + fp2.mulByNonResidue(&c[0], t[0]) +} + +func (e *fp6) mulByNonResidue(c, a *fe6) { + fp2, t := e.fp2, e.t + t[0].set(&a[0]) + fp2.mulByNonResidue(&c[0], &a[2]) + c[2].set(&a[1]) + c[1].set(t[0]) +} + +func (e *fp6) mulByBaseField(c, a *fe6, b *fe2) { + fp2 := e.fp2 + // c0 = a0b0 + // c1 = a1b1 + // c2 = a2b2 + fp2.mul(&c[0], &a[0], b) + fp2.mul(&c[1], &a[1], b) + fp2.mul(&c[2], &a[2], b) +} + +func (e *fp6) exp(c, a *fe6, s *big.Int) { + z := e.one() + for i := s.BitLen() - 1; i >= 0; i-- { + e.square(z, z) + if s.Bit(i) == 1 { + e.mul(z, z, a) + } + } + c.set(z) +} + +func (e *fp6) inverse(c, a *fe6) { + // Guide to Pairing Based Cryptography + // Algorithm 5.23 + + fp2, t := e.fp2, e.t + fp2.square(t[0], &a[0]) + fp2.mul(t[1], &a[1], &a[2]) + fp2.mulByNonResidue(t[1], t[1]) + fp2.subAssign(t[0], t[1]) // A = v0 - βv5 + fp2.square(t[1], &a[1]) // v1 = a1^2 + fp2.mul(t[2], &a[0], &a[2]) // v4 = a0a2 + fp2.subAssign(t[1], t[2]) // C = v1 - v4 + fp2.square(t[2], &a[2]) // v2 = a2^2 + fp2.mulByNonResidue(t[2], t[2]) // βv2 + fp2.mul(t[3], &a[0], &a[1]) // v3 = a0a1 + fp2.subAssign(t[2], t[3]) // B = βv2 - v3 + fp2.mul(t[3], &a[2], t[2]) // B * a2 + fp2.mul(t[4], &a[1], t[1]) // C * a1 + fp2.addAssign(t[3], t[4]) // Ca1 + Ba2 + fp2.mulByNonResidue(t[3], t[3]) // β(Ca1 + Ba2) + fp2.mul(t[4], &a[0], t[0]) // Aa0 + fp2.addAssign(t[3], t[4]) // v6 = Aa0 + β(Ca1 + Ba2) + fp2.inverse(t[3], t[3]) // F = v6^-1 + fp2.mul(&c[0], t[0], t[3]) // c0 = AF + fp2.mul(&c[1], t[2], t[3]) // c1 = BF + fp2.mul(&c[2], t[1], t[3]) // c2 = CF +} + +func (e *fp6) frobeniusMap(a *fe6, power int) { + fp2 := e.fp2 + fp2.frobeniusMap(&a[0], power) + fp2.frobeniusMap(&a[1], power) + fp2.frobeniusMap(&a[2], power) + fp2.mulAssign(&a[1], &frobeniusCoeffs61[power%6]) + fp2.mulAssign(&a[2], &frobeniusCoeffs62[power%6]) +} + +func (e *fp6) frobeniusMap1(a *fe6) { + fp2 := e.fp2 + fp2.frobeniusMap1(&a[0]) + fp2.frobeniusMap1(&a[1]) + fp2.frobeniusMap1(&a[2]) + fp2.mulAssign(&a[1], &frobeniusCoeffs61[1]) + fp2.mulAssign(&a[2], &frobeniusCoeffs62[1]) +} + +func (e *fp6) frobeniusMap2(a *fe6) { + e.fp2.mulAssign(&a[1], &frobeniusCoeffs61[2]) + e.fp2.mulAssign(&a[2], &frobeniusCoeffs62[2]) +} + +func (e *fp6) frobeniusMap3(a *fe6) { + fp2, t := e.fp2, e.t + fp2.frobeniusMap1(&a[0]) + fp2.frobeniusMap1(&a[1]) + fp2.frobeniusMap1(&a[2]) + neg(&t[0][0], &a[1][1]) + a[1][1].set(&a[1][0]) + a[1][0].set(&t[0][0]) + fp2.neg(&a[2], &a[2]) +} diff --git a/vendor/github.com/kilic/bls12-381/fp_fallback.go b/vendor/github.com/kilic/bls12-381/fp_fallback.go new file mode 100644 index 00000000000..84adee3e739 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/fp_fallback.go @@ -0,0 +1,454 @@ +// +build !amd64 generic + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by goff (v0.3.5) DO NOT EDIT + +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + +package bls12381 + +import "math/bits" + +func add(z, x, y *fe) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], carry = bits.Add64(x[3], y[3], carry) + z[4], carry = bits.Add64(x[4], y[4], carry) + z[5], _ = bits.Add64(x[5], y[5], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) + z[1], b = bits.Sub64(z[1], 2210141511517208575, b) + z[2], b = bits.Sub64(z[2], 7435674573564081700, b) + z[3], b = bits.Sub64(z[3], 7239337960414712511, b) + z[4], b = bits.Sub64(z[4], 5412103778470702295, b) + z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) + } +} + +func addAssign(z, y *fe) { + var carry uint64 + + z[0], carry = bits.Add64(z[0], y[0], 0) + z[1], carry = bits.Add64(z[1], y[1], carry) + z[2], carry = bits.Add64(z[2], y[2], carry) + z[3], carry = bits.Add64(z[3], y[3], carry) + z[4], carry = bits.Add64(z[4], y[4], carry) + z[5], _ = bits.Add64(z[5], y[5], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) + z[1], b = bits.Sub64(z[1], 2210141511517208575, b) + z[2], b = bits.Sub64(z[2], 7435674573564081700, b) + z[3], b = bits.Sub64(z[3], 7239337960414712511, b) + z[4], b = bits.Sub64(z[4], 5412103778470702295, b) + z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) + } +} + +func ladd(z, x, y *fe) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], carry = bits.Add64(x[3], y[3], carry) + z[4], carry = bits.Add64(x[4], y[4], carry) + z[5], _ = bits.Add64(x[5], y[5], carry) +} + +func laddAssign(z, y *fe) { + var carry uint64 + + z[0], carry = bits.Add64(z[0], y[0], 0) + z[1], carry = bits.Add64(z[1], y[1], carry) + z[2], carry = bits.Add64(z[2], y[2], carry) + z[3], carry = bits.Add64(z[3], y[3], carry) + z[4], carry = bits.Add64(z[4], y[4], carry) + z[5], _ = bits.Add64(z[5], y[5], carry) +} + +func double(z, x *fe) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], carry = bits.Add64(x[3], x[3], carry) + z[4], carry = bits.Add64(x[4], x[4], carry) + z[5], _ = bits.Add64(x[5], x[5], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) + z[1], b = bits.Sub64(z[1], 2210141511517208575, b) + z[2], b = bits.Sub64(z[2], 7435674573564081700, b) + z[3], b = bits.Sub64(z[3], 7239337960414712511, b) + z[4], b = bits.Sub64(z[4], 5412103778470702295, b) + z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) + } +} + +func doubleAssign(z *fe) { + var carry uint64 + + z[0], carry = bits.Add64(z[0], z[0], 0) + z[1], carry = bits.Add64(z[1], z[1], carry) + z[2], carry = bits.Add64(z[2], z[2], carry) + z[3], carry = bits.Add64(z[3], z[3], carry) + z[4], carry = bits.Add64(z[4], z[4], carry) + z[5], _ = bits.Add64(z[5], z[5], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) + z[1], b = bits.Sub64(z[1], 2210141511517208575, b) + z[2], b = bits.Sub64(z[2], 7435674573564081700, b) + z[3], b = bits.Sub64(z[3], 7239337960414712511, b) + z[4], b = bits.Sub64(z[4], 5412103778470702295, b) + z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) + } +} + +func ldouble(z, x *fe) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], carry = bits.Add64(x[3], x[3], carry) + z[4], carry = bits.Add64(x[4], x[4], carry) + z[5], _ = bits.Add64(x[5], x[5], carry) +} + +func sub(z, x, y *fe) { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + z[4], b = bits.Sub64(x[4], y[4], b) + z[5], b = bits.Sub64(x[5], y[5], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], 13402431016077863595, 0) + z[1], c = bits.Add64(z[1], 2210141511517208575, c) + z[2], c = bits.Add64(z[2], 7435674573564081700, c) + z[3], c = bits.Add64(z[3], 7239337960414712511, c) + z[4], c = bits.Add64(z[4], 5412103778470702295, c) + z[5], _ = bits.Add64(z[5], 1873798617647539866, c) + } +} + +func subAssign(z, y *fe) { + var b uint64 + z[0], b = bits.Sub64(z[0], y[0], 0) + z[1], b = bits.Sub64(z[1], y[1], b) + z[2], b = bits.Sub64(z[2], y[2], b) + z[3], b = bits.Sub64(z[3], y[3], b) + z[4], b = bits.Sub64(z[4], y[4], b) + z[5], b = bits.Sub64(z[5], y[5], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], 13402431016077863595, 0) + z[1], c = bits.Add64(z[1], 2210141511517208575, c) + z[2], c = bits.Add64(z[2], 7435674573564081700, c) + z[3], c = bits.Add64(z[3], 7239337960414712511, c) + z[4], c = bits.Add64(z[4], 5412103778470702295, c) + z[5], _ = bits.Add64(z[5], 1873798617647539866, c) + } +} + +func lsubAssign(z, y *fe) { + var b uint64 + z[0], b = bits.Sub64(z[0], y[0], 0) + z[1], b = bits.Sub64(z[1], y[1], b) + z[2], b = bits.Sub64(z[2], y[2], b) + z[3], b = bits.Sub64(z[3], y[3], b) + z[4], b = bits.Sub64(z[4], y[4], b) + z[5], b = bits.Sub64(z[5], y[5], b) +} + +func neg(z, x *fe) { + if x.isZero() { + z.zero() + return + } + var borrow uint64 + z[0], borrow = bits.Sub64(13402431016077863595, x[0], 0) + z[1], borrow = bits.Sub64(2210141511517208575, x[1], borrow) + z[2], borrow = bits.Sub64(7435674573564081700, x[2], borrow) + z[3], borrow = bits.Sub64(7239337960414712511, x[3], borrow) + z[4], borrow = bits.Sub64(5412103778470702295, x[4], borrow) + z[5], _ = bits.Sub64(1873798617647539866, x[5], borrow) +} + +func mul(z, x, y *fe) { + + var t [6]uint64 + var c [3]uint64 + { + // round 0 + v := x[0] + c[1], c[0] = bits.Mul64(v, y[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd1(v, y[1], c[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd1(v, y[2], c[1]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd1(v, y[3], c[1]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd1(v, y[4], c[1]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd1(v, y[5], c[1]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 1 + v := x[1] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 2 + v := x[2] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 3 + v := x[3] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 4 + v := x[4] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 5 + v := x[5] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], z[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], z[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + c[2], z[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, y[4], c[1], t[4]) + c[2], z[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, y[5], c[1], t[5]) + z[5], z[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) + z[1], b = bits.Sub64(z[1], 2210141511517208575, b) + z[2], b = bits.Sub64(z[2], 7435674573564081700, b) + z[3], b = bits.Sub64(z[3], 7239337960414712511, b) + z[4], b = bits.Sub64(z[4], 5412103778470702295, b) + z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) + } +} + +func square(z, x *fe) { + + var t [6]uint64 + var c [3]uint64 + { + // round 0 + v := x[0] + c[1], c[0] = bits.Mul64(v, x[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd1(v, x[1], c[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd1(v, x[2], c[1]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd1(v, x[3], c[1]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd1(v, x[4], c[1]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd1(v, x[5], c[1]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 1 + v := x[1] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, x[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, x[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 2 + v := x[2] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, x[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, x[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 3 + v := x[3] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, x[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, x[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 4 + v := x[4] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], t[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], t[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + c[2], t[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, x[4], c[1], t[4]) + c[2], t[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, x[5], c[1], t[5]) + t[5], t[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + { + // round 5 + v := x[5] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 9940570264628428797 + c[2] = madd0(m, 13402431016077863595, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], z[0] = madd2(m, 2210141511517208575, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], z[1] = madd2(m, 7435674573564081700, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + c[2], z[2] = madd2(m, 7239337960414712511, c[2], c[0]) + c[1], c[0] = madd2(v, x[4], c[1], t[4]) + c[2], z[3] = madd2(m, 5412103778470702295, c[2], c[0]) + c[1], c[0] = madd2(v, x[5], c[1], t[5]) + z[5], z[4] = madd3(m, 1873798617647539866, c[0], c[2], c[1]) + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[5] < 1873798617647539866 || (z[5] == 1873798617647539866 && (z[4] < 5412103778470702295 || (z[4] == 5412103778470702295 && (z[3] < 7239337960414712511 || (z[3] == 7239337960414712511 && (z[2] < 7435674573564081700 || (z[2] == 7435674573564081700 && (z[1] < 2210141511517208575 || (z[1] == 2210141511517208575 && (z[0] < 13402431016077863595))))))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 13402431016077863595, 0) + z[1], b = bits.Sub64(z[1], 2210141511517208575, b) + z[2], b = bits.Sub64(z[2], 7435674573564081700, b) + z[3], b = bits.Sub64(z[3], 7239337960414712511, b) + z[4], b = bits.Sub64(z[4], 5412103778470702295, b) + z[5], _ = bits.Sub64(z[5], 1873798617647539866, b) + } +} diff --git a/vendor/github.com/kilic/bls12-381/fr.go b/vendor/github.com/kilic/bls12-381/fr.go new file mode 100644 index 00000000000..fd17e5d1806 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/fr.go @@ -0,0 +1,383 @@ +package bls12381 + +import ( + "crypto/rand" + "io" + "math/big" +) + +const frByteSize = 32 +const frBitSize = 255 +const frNumberOfLimbs = 4 +const fourWordBitSize = 256 + +type Fr [4]uint64 +type wideFr [8]uint64 + +func NewFr() *Fr { + return &Fr{} +} + +func (e *Fr) Rand(r io.Reader) (*Fr, error) { + bi, err := rand.Int(r, qBig) + if err != nil { + return nil, err + } + _ = e.fromBig(bi) + return e, nil +} + +func (e *Fr) Set(e2 *Fr) *Fr { + e[0] = e2[0] + e[1] = e2[1] + e[2] = e2[2] + e[3] = e2[3] + return e +} + +func (e *Fr) Zero() *Fr { + e[0] = 0 + e[1] = 0 + e[2] = 0 + e[3] = 0 + return e +} + +func (e *Fr) One() *Fr { + e.Set(&Fr{1}) + return e +} + +func (e *Fr) RedOne() *Fr { + e.Set(qr1) + return e +} + +func (e *Fr) FromBytes(in []byte) *Fr { + e.fromBytes(in) + return e +} + +func (e *Fr) RedFromBytes(in []byte) *Fr { + e.fromBytes(in) + e.toMont() + return e +} + +func (e *Fr) fromBytes(in []byte) *Fr { + u := new(big.Int).SetBytes(in) + _ = e.fromBig(u) + return e +} + +func (e *Fr) fromBig(in *big.Int) *Fr { + e.Zero() + _in := new(big.Int).Set(in) + zero := new(big.Int) + c0 := _in.Cmp(zero) + c1 := _in.Cmp(qBig) + if c0 == -1 || c1 == 1 { + _in.Mod(_in, qBig) + } + words := _in.Bits() + for i := 0; i < len(words); i++ { + e[i] = uint64(words[i]) + } + return e +} + +func (e *Fr) setUint64(n uint64) *Fr { + e.Zero() + e[0] = n + return e +} + +func (e *Fr) ToBytes() []byte { + return NewFr().Set(e).bytes() +} + +func (e *Fr) RedToBytes() []byte { + out := NewFr().Set(e) + out.fromMont() + return out.bytes() +} + +func (e *Fr) ToBig() *big.Int { + return new(big.Int).SetBytes(e.ToBytes()) +} + +func (e *Fr) RedToBig() *big.Int { + return new(big.Int).SetBytes(e.RedToBytes()) +} + +func (e *Fr) bytes() []byte { + out := make([]byte, frByteSize) + var a int + for i := 0; i < frNumberOfLimbs; i++ { + a = frByteSize - i*8 + out[a-1] = byte(e[i]) + out[a-2] = byte(e[i] >> 8) + out[a-3] = byte(e[i] >> 16) + out[a-4] = byte(e[i] >> 24) + out[a-5] = byte(e[i] >> 32) + out[a-6] = byte(e[i] >> 40) + out[a-7] = byte(e[i] >> 48) + out[a-8] = byte(e[i] >> 56) + } + return out +} + +func (e *Fr) IsZero() bool { + return (e[3] | e[2] | e[1] | e[0]) == 0 +} + +func (e *Fr) IsOne() bool { + return e.Equal(&Fr{1}) +} + +func (e *Fr) IsRedOne() bool { + return e.Equal(qr1) +} + +func (e *Fr) Equal(e2 *Fr) bool { + return e2[0] == e[0] && e2[1] == e[1] && e2[2] == e[2] && e2[3] == e[3] +} + +func (e *Fr) Cmp(e1 *Fr) int { + for i := frNumberOfLimbs - 1; i >= 0; i-- { + if e[i] > e1[i] { + return 1 + } else if e[i] < e1[i] { + return -1 + } + } + return 0 +} + +func (e *Fr) sliceUint64(from int) uint64 { + if from < 64 { + return e[0]>>from | e[1]<<(64-from) + } else if from < 128 { + return e[1]>>(from-64) | e[2]<<(128-from) + } else if from < 192 { + return e[2]>>(from-128) | e[3]<<(192-from) + } + return e[3] >> (from - 192) +} + +func (e *Fr) div2() { + e[0] = e[0]>>1 | e[1]<<63 + e[1] = e[1]>>1 | e[2]<<63 + e[2] = e[2]>>1 | e[3]<<63 + e[3] = e[3] >> 1 +} + +func (e *Fr) mul2() uint64 { + c := e[3] >> 63 + e[3] = e[3]<<1 | e[2]>>63 + e[2] = e[2]<<1 | e[1]>>63 + e[1] = e[1]<<1 | e[0]>>63 + e[0] = e[0] << 1 + return c +} + +func (e *Fr) isEven() bool { + var mask uint64 = 1 + return e[0]&mask == 0 +} + +func (e *Fr) Bit(at int) bool { + if at < 64 { + return (e[0]>>at)&1 == 1 + } else if at < 128 { + return (e[1]>>(at-64))&1 == 1 + } else if at < 192 { + return (e[2]>>(at-128))&1 == 1 + } else if at < 256 { + return (e[3]>>(at-192))&1 == 1 + } + return false +} + +func (e *Fr) toMont() { + e.RedMul(e, qr2) +} + +func (e *Fr) fromMont() { + e.RedMul(e, &Fr{1}) +} + +func (e *Fr) FromRed() { + e.fromMont() +} + +func (e *Fr) ToRed() { + e.toMont() +} + +func (e *Fr) Add(a, b *Fr) { + addFR(e, a, b) +} + +func (e *Fr) Double(a *Fr) { + doubleFR(e, a) +} + +func (e *Fr) Sub(a, b *Fr) { + subFR(e, a, b) +} + +func (e *Fr) Neg(a *Fr) { + negFR(e, a) +} + +func (e *Fr) Mul(a, b *Fr) { + e.RedMul(a, b) + e.toMont() +} + +func (e *Fr) RedMul(a, b *Fr) { + mulFR(e, a, b) +} + +func (e *Fr) Square(a *Fr) { + e.RedSquare(a) + e.toMont() +} + +func (e *Fr) RedSquare(a *Fr) { + squareFR(e, a) +} + +func (e *Fr) RedExp(a *Fr, ee *big.Int) { + z := new(Fr).RedOne() + for i := ee.BitLen(); i >= 0; i-- { + z.RedSquare(z) + if ee.Bit(i) == 1 { + z.RedMul(z, a) + } + } + e.Set(z) +} + +func (e *Fr) Exp(a *Fr, ee *big.Int) { + e.Set(a).toMont() + e.RedExp(e, ee) + e.fromMont() + +} + +func (e *Fr) Inverse(a *Fr) { + e.Set(a).toMont() + e.RedInverse(e) + e.fromMont() +} + +func (e *Fr) RedInverse(ei *Fr) { + if ei.IsZero() { + e.Zero() + return + } + u := new(Fr).Set(&q) + v := new(Fr).Set(ei) + s := &Fr{1} + r := &Fr{0} + var k int + var z uint64 + var found = false + // Phase 1 + for i := 0; i < fourWordBitSize*2; i++ { + if v.IsZero() { + found = true + break + } + if u.isEven() { + u.div2() + s.mul2() + } else if v.isEven() { + v.div2() + z += r.mul2() + } else if u.Cmp(v) == 1 { + lsubAssignFR(u, v) + u.div2() + laddAssignFR(r, s) + s.mul2() + } else { + lsubAssignFR(v, u) + v.div2() + laddAssignFR(s, r) + z += r.mul2() + } + k += 1 + } + + if !found { + e.Zero() + return + } + + if k < frBitSize || k > frBitSize+fourWordBitSize { + e.Zero() + return + } + + if r.Cmp(&q) != -1 || z > 0 { + lsubAssignFR(r, &q) + } + u.Set(&q) + lsubAssignFR(u, r) + + // Phase 2 + for i := k; i < 2*fourWordBitSize; i++ { + doubleFR(u, u) + } + e.Set(u) +} + +func (ew *wideFr) mul(a, b *Fr) { + lmulFR(ew, a, b) +} + +func (ew *wideFr) add(a *wideFr) { + addwFR(ew, a) +} + +func (ew *wideFr) round() *Fr { + ew.add(halfR) + return ew.high() +} + +func (ew *wideFr) high() *Fr { + e := new(Fr) + e[0] = ew[4] + e[1] = ew[5] + e[2] = ew[6] + e[3] = ew[7] + return e +} + +func (ew *wideFr) low() *Fr { + e := new(Fr) + e[0] = ew[0] + e[1] = ew[1] + e[2] = ew[2] + e[3] = ew[3] + return e +} + +func (e *wideFr) bytes() []byte { + out := make([]byte, frByteSize*2) + var a int + for i := 0; i < frNumberOfLimbs*2; i++ { + a = frByteSize*2 - i*8 + out[a-1] = byte(e[i]) + out[a-2] = byte(e[i] >> 8) + out[a-3] = byte(e[i] >> 16) + out[a-4] = byte(e[i] >> 24) + out[a-5] = byte(e[i] >> 32) + out[a-6] = byte(e[i] >> 40) + out[a-7] = byte(e[i] >> 48) + out[a-8] = byte(e[i] >> 56) + } + return out +} diff --git a/vendor/github.com/kilic/bls12-381/fr_fallback.go b/vendor/github.com/kilic/bls12-381/fr_fallback.go new file mode 100644 index 00000000000..ae5bb747302 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/fr_fallback.go @@ -0,0 +1,386 @@ +// +build !amd64 generic + +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by goff (v0.3.5) DO NOT EDIT + +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + +package bls12381 + +import "math/bits" + +func addFR(z, x, y *Fr) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], y[0], 0) + z[1], carry = bits.Add64(x[1], y[1], carry) + z[2], carry = bits.Add64(x[2], y[2], carry) + z[3], _ = bits.Add64(x[3], y[3], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 18446744069414584321, 0) + z[1], b = bits.Sub64(z[1], 6034159408538082302, b) + z[2], b = bits.Sub64(z[2], 3691218898639771653, b) + z[3], _ = bits.Sub64(z[3], 8353516859464449352, b) + } +} + +func laddAssignFR(z, y *Fr) { + var carry uint64 + + z[0], carry = bits.Add64(z[0], y[0], 0) + z[1], carry = bits.Add64(z[1], y[1], carry) + z[2], carry = bits.Add64(z[2], y[2], carry) + z[3], _ = bits.Add64(z[3], y[3], carry) +} + +func doubleFR(z, x *Fr) { + var carry uint64 + + z[0], carry = bits.Add64(x[0], x[0], 0) + z[1], carry = bits.Add64(x[1], x[1], carry) + z[2], carry = bits.Add64(x[2], x[2], carry) + z[3], _ = bits.Add64(x[3], x[3], carry) + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 18446744069414584321, 0) + z[1], b = bits.Sub64(z[1], 6034159408538082302, b) + z[2], b = bits.Sub64(z[2], 3691218898639771653, b) + z[3], _ = bits.Sub64(z[3], 8353516859464449352, b) + } +} + +func subFR(z, x, y *Fr) { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + z[1], b = bits.Sub64(x[1], y[1], b) + z[2], b = bits.Sub64(x[2], y[2], b) + z[3], b = bits.Sub64(x[3], y[3], b) + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], 18446744069414584321, 0) + z[1], c = bits.Add64(z[1], 6034159408538082302, c) + z[2], c = bits.Add64(z[2], 3691218898639771653, c) + z[3], _ = bits.Add64(z[3], 8353516859464449352, c) + } +} + +func lsubAssignFR(z, y *Fr) { + var b uint64 + z[0], b = bits.Sub64(z[0], y[0], 0) + z[1], b = bits.Sub64(z[1], y[1], b) + z[2], b = bits.Sub64(z[2], y[2], b) + z[3], b = bits.Sub64(z[3], y[3], b) +} + +func negFR(z, x *Fr) { + if x.IsZero() { + z.Zero() + return + } + var borrow uint64 + z[0], borrow = bits.Sub64(18446744069414584321, x[0], 0) + z[1], borrow = bits.Sub64(6034159408538082302, x[1], borrow) + z[2], borrow = bits.Sub64(3691218898639771653, x[2], borrow) + z[3], _ = bits.Sub64(8353516859464449352, x[3], borrow) +} + +func mulFR(z, x, y *Fr) { + + var t [4]uint64 + var c [3]uint64 + { + // round 0 + v := x[0] + c[1], c[0] = bits.Mul64(v, y[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd1(v, y[1], c[1]) + c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd1(v, y[2], c[1]) + c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd1(v, y[3], c[1]) + t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + { + // round 1 + v := x[1] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + { + // round 2 + v := x[2] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + { + // round 3 + v := x[3] + c[1], c[0] = madd1(v, y[0], t[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd2(v, y[1], c[1], t[1]) + c[2], z[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd2(v, y[2], c[1], t[2]) + c[2], z[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd2(v, y[3], c[1], t[3]) + z[3], z[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 18446744069414584321, 0) + z[1], b = bits.Sub64(z[1], 6034159408538082302, b) + z[2], b = bits.Sub64(z[2], 3691218898639771653, b) + z[3], _ = bits.Sub64(z[3], 8353516859464449352, b) + } +} + +func squareFR(z, x *Fr) { + + var t [4]uint64 + var c [3]uint64 + { + // round 0 + v := x[0] + c[1], c[0] = bits.Mul64(v, x[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd1(v, x[1], c[1]) + c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd1(v, x[2], c[1]) + c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd1(v, x[3], c[1]) + t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + { + // round 1 + v := x[1] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + { + // round 2 + v := x[2] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], t[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], t[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + t[3], t[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + { + // round 3 + v := x[3] + c[1], c[0] = madd1(v, x[0], t[0]) + m := c[0] * 18446744069414584319 + c[2] = madd0(m, 18446744069414584321, c[0]) + c[1], c[0] = madd2(v, x[1], c[1], t[1]) + c[2], z[0] = madd2(m, 6034159408538082302, c[2], c[0]) + c[1], c[0] = madd2(v, x[2], c[1], t[2]) + c[2], z[1] = madd2(m, 3691218898639771653, c[2], c[0]) + c[1], c[0] = madd2(v, x[3], c[1], t[3]) + z[3], z[2] = madd3(m, 8353516859464449352, c[0], c[2], c[1]) + } + + // if z > q --> z -= q + // note: this is NOT constant time + if !(z[3] < 8353516859464449352 || (z[3] == 8353516859464449352 && (z[2] < 3691218898639771653 || (z[2] == 3691218898639771653 && (z[1] < 6034159408538082302 || (z[1] == 6034159408538082302 && (z[0] < 18446744069414584321))))))) { + var b uint64 + z[0], b = bits.Sub64(z[0], 18446744069414584321, 0) + z[1], b = bits.Sub64(z[1], 6034159408538082302, b) + z[2], b = bits.Sub64(z[2], 3691218898639771653, b) + z[3], _ = bits.Sub64(z[3], 8353516859464449352, b) + } +} + +func addwFR(z, y *wideFr) { + var carry uint64 + z[0], carry = bits.Add64(z[0], y[0], 0) + z[1], carry = bits.Add64(z[1], y[1], carry) + z[2], carry = bits.Add64(z[2], y[2], carry) + z[3], carry = bits.Add64(z[3], y[3], carry) + z[4], carry = bits.Add64(z[4], y[4], carry) + z[5], carry = bits.Add64(z[5], y[5], carry) + z[6], carry = bits.Add64(z[6], y[6], carry) + z[7], _ = bits.Add64(z[7], y[7], carry) +} + +// We applied custom multiplication since goff does generate multiplication code nested with reduction +func lmulFR(w *wideFr, a, b *Fr) { + // Handbook of Applied Cryptography + // Hankerson, Menezes, Vanstone + // 14.12 Algorithm Multiple-precision multiplication + + var w0, w1, w2, w3, w4, w5, w6, w7 uint64 + var a0 = a[0] + var a1 = a[1] + var a2 = a[2] + var a3 = a[3] + var b0 = b[0] + var b1 = b[1] + var b2 = b[2] + var b3 = b[3] + var u, v, c, t uint64 + + // i = 0, j = 0 + c, w0 = bits.Mul64(a0, b0) + + // i = 0, j = 1 + u, v = bits.Mul64(a1, b0) + w1 = v + c + c = u + (v&c|(v|c)&^w1)>>63 + + // i = 0, j = 2 + u, v = bits.Mul64(a2, b0) + w2 = v + c + c = u + (v&c|(v|c)&^w2)>>63 + + // i = 0, j = 3 + u, v = bits.Mul64(a3, b0) + w3 = v + c + w4 = u + (v&c|(v|c)&^w3)>>63 + + // + // i = 1, j = 0 + c, v = bits.Mul64(a0, b1) + t = v + w1 + c += (v&w1 | (v|w1)&^t) >> 63 + w1 = t + + // i = 1, j = 1 + u, v = bits.Mul64(a1, b1) + t = v + w2 + u += (v&w2 | (v|w2)&^t) >> 63 + w2 = t + c + c = u + (t&c|(t|c)&^w2)>>63 + + // i = 1, j = 2 + u, v = bits.Mul64(a2, b1) + t = v + w3 + u += (v&w3 | (v|w3)&^t) >> 63 + w3 = t + c + c = u + (t&c|(t|c)&^w3)>>63 + + // i = 1, j = 3 + u, v = bits.Mul64(a3, b1) + t = v + w4 + u += (v&w4 | (v|w4)&^t) >> 63 + w4 = t + c + w5 = u + (t&c|(t|c)&^w4)>>63 + + // + // i = 2, j = 0 + c, v = bits.Mul64(a0, b2) + t = v + w2 + c += (v&w2 | (v|w2)&^t) >> 63 + w2 = t + + // i = 2, j = 1 + u, v = bits.Mul64(a1, b2) + t = v + w3 + u += (v&w3 | (v|w3)&^t) >> 63 + w3 = t + c + c = u + (t&c|(t|c)&^w3)>>63 + + // i = 2, j = 2 + u, v = bits.Mul64(a2, b2) + t = v + w4 + u += (v&w4 | (v|w4)&^t) >> 63 + w4 = t + c + c = u + (t&c|(t|c)&^w4)>>63 + + // i = 2, j = 3 + u, v = bits.Mul64(a3, b2) + t = v + w5 + u += (v&w5 | (v|w5)&^t) >> 63 + w5 = t + c + w6 = u + (t&c|(t|c)&^w5)>>63 + + // + // i = 3, j = 0 + c, v = bits.Mul64(a0, b3) + t = v + w3 + c += (v&w3 | (v|w3)&^t) >> 63 + w3 = t + + // i = 3, j = 1 + u, v = bits.Mul64(a1, b3) + t = v + w4 + u += (v&w4 | (v|w4)&^t) >> 63 + w4 = t + c + c = u + (t&c|(t|c)&^w4)>>63 + + // i = 3, j = 2 + u, v = bits.Mul64(a2, b3) + t = v + w5 + u += (v&w5 | (v|w5)&^t) >> 63 + w5 = t + c + c = u + (t&c|(t|c)&^w5)>>63 + + // i = 3, j = 3 + u, v = bits.Mul64(a3, b3) + t = v + w6 + u += (v&w6 | (v|w6)&^t) >> 63 + w6 = t + c + w7 = u + (t&c|(t|c)&^w6)>>63 + + w[0] = w0 + w[1] = w1 + w[2] = w2 + w[3] = w3 + w[4] = w4 + w[5] = w5 + w[6] = w6 + w[7] = w7 +} diff --git a/vendor/github.com/kilic/bls12-381/g1.go b/vendor/github.com/kilic/bls12-381/g1.go new file mode 100644 index 00000000000..20e54ffcecb --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/g1.go @@ -0,0 +1,846 @@ +package bls12381 + +import ( + "errors" + "math" + "math/big" +) + +// PointG1 is type for point in G1 and used for both Affine and Jacobian point representation. +// A point is accounted as in affine form if z is equal to one. +type PointG1 [3]fe + +var wnafMulWindowG1 uint = 5 + +func (p *PointG1) Set(p2 *PointG1) *PointG1 { + p[0].set(&p2[0]) + p[1].set(&p2[1]) + p[2].set(&p2[2]) + return p +} + +func (p *PointG1) Zero() *PointG1 { + p[0].zero() + p[1].one() + p[2].zero() + return p +} + +// IsAffine checks a G1 point whether it is in affine form. +func (p *PointG1) IsAffine() bool { + return p[2].isOne() +} + +type tempG1 struct { + t [9]*fe +} + +// G1 is struct for G1 group. +type G1 struct { + tempG1 +} + +// NewG1 constructs a new G1 instance. +func NewG1() *G1 { + t := newTempG1() + return &G1{t} +} + +func newTempG1() tempG1 { + t := [9]*fe{} + for i := 0; i < 9; i++ { + t[i] = &fe{} + } + return tempG1{t} +} + +// Q returns group order in big.Int. +func (g *G1) Q() *big.Int { + return new(big.Int).Set(qBig) +} + +// FromUncompressed expects byte slice at least 96 bytes and given bytes returns a new point in G1. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G1) FromUncompressed(uncompressed []byte) (*PointG1, error) { + if len(uncompressed) != 2*fpByteSize { + return nil, errors.New("input string length must be equal to 96 bytes") + } + var in [2 * fpByteSize]byte + copy(in[:], uncompressed[:2*fpByteSize]) + if in[0]&(1<<7) != 0 { + return nil, errors.New("compression flag must be zero") + } + if in[0]&(1<<5) != 0 { + return nil, errors.New("sort flag must be zero") + } + if in[0]&(1<<6) != 0 { + for i, v := range in { + if (i == 0 && v != 0x40) || (i != 0 && v != 0x00) { + return nil, errors.New("input string must be zero when infinity flag is set") + } + } + return g.Zero(), nil + } + in[0] &= 0x1f + x, err := fromBytes(in[:fpByteSize]) + if err != nil { + return nil, err + } + y, err := fromBytes(in[fpByteSize:]) + if err != nil { + return nil, err + } + z := new(fe).one() + p := &PointG1{*x, *y, *z} + if !g.IsOnCurve(p) { + return nil, errors.New("point is not on curve") + } + if !g.InCorrectSubgroup(p) { + return nil, errors.New("point is not on correct subgroup") + } + return p, nil +} + +// ToUncompressed given a G1 point returns bytes in uncompressed (x, y) form of the point. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G1) ToUncompressed(p *PointG1) []byte { + out := make([]byte, 2*fpByteSize) + if g.IsZero(p) { + out[0] |= 1 << 6 + return out + } + g.Affine(p) + copy(out[:fpByteSize], toBytes(&p[0])) + copy(out[fpByteSize:], toBytes(&p[1])) + return out +} + +// FromCompressed expects byte slice at least 48 bytes and given bytes returns a new point in G1. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G1) FromCompressed(compressed []byte) (*PointG1, error) { + if len(compressed) != fpByteSize { + return nil, errors.New("input string length must be equal to 48 bytes") + } + var in [fpByteSize]byte + copy(in[:], compressed[:]) + if in[0]&(1<<7) == 0 { + return nil, errors.New("compression flag must be set") + } + if in[0]&(1<<6) != 0 { + // in[0] == (1 << 6) + (1 << 7) + for i, v := range in { + if (i == 0 && v != 0xc0) || (i != 0 && v != 0x00) { + return nil, errors.New("input string must be zero when infinity flag is set") + } + } + return g.Zero(), nil + } + a := in[0]&(1<<5) != 0 + in[0] &= 0x1f + x, err := fromBytes(in[:]) + if err != nil { + return nil, err + } + // solve curve equation + y := &fe{} + square(y, x) + mul(y, y, x) + add(y, y, b) + if ok := sqrt(y, y); !ok { + return nil, errors.New("point is not on curve") + } + if y.signBE() == a { + neg(y, y) + } + z := new(fe).one() + p := &PointG1{*x, *y, *z} + if !g.InCorrectSubgroup(p) { + return nil, errors.New("point is not on correct subgroup") + } + return p, nil +} + +// ToCompressed given a G1 point returns bytes in compressed form of the point. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G1) ToCompressed(p *PointG1) []byte { + out := make([]byte, fpByteSize) + g.Affine(p) + if g.IsZero(p) { + out[0] |= 1 << 6 + } else { + copy(out[:], toBytes(&p[0])) + if !p[1].signBE() { + out[0] |= 1 << 5 + } + } + out[0] |= 1 << 7 + return out +} + +func (g *G1) fromBytesUnchecked(in []byte) (*PointG1, error) { + p0, err := fromBytes(in[:fpByteSize]) + if err != nil { + return nil, err + } + p1, err := fromBytes(in[fpByteSize:]) + if err != nil { + return nil, err + } + p2 := new(fe).one() + return &PointG1{*p0, *p1, *p2}, nil +} + +// FromBytes constructs a new point given uncompressed byte input. +// Input string is expected to be equal to 96 bytes and concatenation of x and y cooridanates. +// (0, 0) is considered as infinity. +func (g *G1) FromBytes(in []byte) (*PointG1, error) { + if len(in) != 2*fpByteSize { + return nil, errors.New("input string length must be equal to 96 bytes") + } + p0, err := fromBytes(in[:fpByteSize]) + if err != nil { + return nil, err + } + p1, err := fromBytes(in[fpByteSize:]) + if err != nil { + return nil, err + } + // check if given input points to infinity + if p0.isZero() && p1.isZero() { + return g.Zero(), nil + } + p2 := new(fe).one() + p := &PointG1{*p0, *p1, *p2} + if !g.IsOnCurve(p) { + return nil, errors.New("point is not on curve") + } + return p, nil +} + +// ToBytes serializes a point into bytes in uncompressed form. +// ToBytes returns (0, 0) if point is infinity. +func (g *G1) ToBytes(p *PointG1) []byte { + out := make([]byte, 2*fpByteSize) + if g.IsZero(p) { + return out + } + g.Affine(p) + copy(out[:fpByteSize], toBytes(&p[0])) + copy(out[fpByteSize:], toBytes(&p[1])) + return out +} + +// New creates a new G1 Point which is equal to zero in other words point at infinity. +func (g *G1) New() *PointG1 { + return g.Zero() +} + +// Zero returns a new G1 Point which is equal to point at infinity. +func (g *G1) Zero() *PointG1 { + return new(PointG1).Zero() +} + +// One returns a new G1 Point which is equal to generator point. +func (g *G1) One() *PointG1 { + p := &PointG1{} + return p.Set(&g1One) +} + +// IsZero returns true if given point is equal to zero. +func (g *G1) IsZero(p *PointG1) bool { + return p[2].isZero() +} + +// Equal checks if given two G1 point is equal in their affine form. +func (g *G1) Equal(p1, p2 *PointG1) bool { + if g.IsZero(p1) { + return g.IsZero(p2) + } + if g.IsZero(p2) { + return g.IsZero(p1) + } + t := g.t + square(t[0], &p1[2]) + square(t[1], &p2[2]) + mul(t[2], t[0], &p2[0]) + mul(t[3], t[1], &p1[0]) + mul(t[0], t[0], &p1[2]) + mul(t[1], t[1], &p2[2]) + mul(t[1], t[1], &p1[1]) + mul(t[0], t[0], &p2[1]) + return t[0].equal(t[1]) && t[2].equal(t[3]) +} + +// InCorrectSubgroup checks whether given point is in correct subgroup. +func (g *G1) InCorrectSubgroup(p *PointG1) bool { + + // Faster Subgroup Checks for BLS12-381 + // S. Bowe + // https://eprint.iacr.org/2019/814.pdf + + mulZ := func(p *PointG1) { + // z = [(x^2 − 1)/3] + z := &Fr{0x0000000055555555, 0x396c8c005555e156} + e := z.toWNAF(wnafMulWindowG1) + g.wnafMul(p, p, e) + } + + // [(x^2 − 1)/3](2σ(P) − P − σ^2(P)) − σ^2(P) ?= O + t0 := g.New().Set(p) + g.glvEndomorphism(t0, t0) + t1 := g.New().Set(t0) // σ(P) + g.glvEndomorphism(t0, t0) // σ^2(P) + g.Double(t1, t1) // 2σ(P) + g.Sub(t1, t1, p) // 2σ(P) − P + g.Sub(t1, t1, t0) // 2σ(P) − P − σ^2(P) + mulZ(t1) // [(x^2 − 1)/3](2σ(P) − P − σ^2(P)) + g.Sub(t1, t1, t0) // [(x^2 − 1)/3](2σ(P) − P − σ^2(P)) − σ^2(P) + return g.IsZero(t1) +} + +// IsOnCurve checks a G1 point is on curve. +func (g *G1) IsOnCurve(p *PointG1) bool { + if g.IsZero(p) { + return true + } + t := g.t + square(t[0], &p[1]) // y^2 + square(t[1], &p[0]) // x^2 + mul(t[1], t[1], &p[0]) // x^3 + if p.IsAffine() { + addAssign(t[1], b) // x^2 + b + return t[0].equal(t[1]) // y^2 ?= x^3 + b + } + square(t[2], &p[2]) // z^2 + square(t[3], t[2]) // z^4 + mul(t[2], t[2], t[3]) // z^6 + mul(t[2], b, t[2]) // b * z^6 + add(t[1], t[1], t[2]) // x^3 + b * z^6 + return t[0].equal(t[1]) // y^2 ?= x^3 + b * z^6 +} + +// IsAffine checks a G1 point whether it is in affine form. +func (g *G1) IsAffine(p *PointG1) bool { + return p[2].isOne() +} + +// Affine returns the affine representation of the given point +func (g *G1) Affine(p *PointG1) *PointG1 { + return g.affine(p, p) +} + +func (g *G1) affine(r, p *PointG1) *PointG1 { + if g.IsZero(p) { + return r.Zero() + } + if !g.IsAffine(p) { + t := g.t + inverse(t[0], &p[2]) // z^-1 + square(t[1], t[0]) // z^-2 + mul(&r[0], &p[0], t[1]) // x = x * z^-2 + mul(t[0], t[0], t[1]) // z^-3 + mul(&r[1], &p[1], t[0]) // y = y * z^-3 + r[2].one() // z = 1 + } else { + r.Set(p) + } + return r +} + +// AffineBatch given multiple of points returns affine representations +func (g *G1) AffineBatch(p []*PointG1) { + inverses := make([]fe, len(p)) + for i := 0; i < len(p); i++ { + inverses[i].set(&p[i][2]) + } + inverseBatch(inverses) + t := g.t + for i := 0; i < len(p); i++ { + if !g.IsAffine(p[i]) && !g.IsZero(p[i]) { + square(t[1], &inverses[i]) + mul(&p[i][0], &p[i][0], t[1]) + mul(t[0], &inverses[i], t[1]) + mul(&p[i][1], &p[i][1], t[0]) + p[i][2].one() + } + } +} + +// Add adds two G1 points p1, p2 and assigns the result to point at first argument. +func (g *G1) Add(r, p1, p2 *PointG1) *PointG1 { + + // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#addition-add-2007-bl + if g.IsZero(p1) { + return r.Set(p2) + } + if g.IsZero(p2) { + return r.Set(p1) + } + if g.IsAffine(p2) { + return g.AddMixed(r, p1, p2) + } + t := g.t + square(t[7], &p1[2]) // z1z1 + mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1 + mul(t[2], &p1[2], t[7]) // z1z1 * z1 + mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1 + square(t[8], &p2[2]) // z2z2 + mul(t[3], &p1[0], t[8]) // u1 = x1 * z2z2 + mul(t[4], &p2[2], t[8]) // z2z2 * z2 + mul(t[2], &p1[1], t[4]) // s1 = y1 * z2z2 * z2 + if t[1].equal(t[3]) { + if t[0].equal(t[2]) { + return g.Double(r, p1) + } else { + return r.Zero() + } + } + subAssign(t[1], t[3]) // h = u2 - u1 + double(t[4], t[1]) // 2h + square(t[4], t[4]) // i = 2h^2 + mul(t[5], t[1], t[4]) // j = h*i + subAssign(t[0], t[2]) // s2 - s1 + doubleAssign(t[0]) // r = 2*(s2 - s1) + square(t[6], t[0]) // r^2 + subAssign(t[6], t[5]) // r^2 - j + mul(t[3], t[3], t[4]) // v = u1 * i + double(t[4], t[3]) // 2*v + sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v + sub(t[4], t[3], &r[0]) // v - x3 + mul(t[6], t[2], t[5]) // s1 * j + doubleAssign(t[6]) // 2 * s1 * j + mul(t[0], t[0], t[4]) // r * (v - x3) + sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * s1 * j) + add(t[0], &p1[2], &p2[2]) // z1 + z2 + square(t[0], t[0]) // (z1 + z2)^2 + subAssign(t[0], t[7]) // (z1 + z2)^2 - z1z1 + subAssign(t[0], t[8]) // (z1 + z2)^2 - z1z1 - z2z2 + mul(&r[2], t[0], t[1]) // z3 = ((z1 + z2)^2 - z1z1 - z2z2) * h + return r +} + +// Add adds two G1 points p1, p2 and assigns the result to point at first argument. +// Expects the second point p2 in affine form. +func (g *G1) AddMixed(r, p1, p2 *PointG1) *PointG1 { + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + if g.IsZero(p1) { + return r.Set(p2) + } + if g.IsZero(p2) { + return r.Set(p1) + } + t := g.t + square(t[7], &p1[2]) // z1z1 + mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1 + mul(t[2], &p1[2], t[7]) // z1z1 * z1 + mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1 + + if p1[0].equal(t[1]) && p1[1].equal(t[0]) { + return g.Double(r, p1) + } + + sub(t[1], t[1], &p1[0]) // h = u2 - x1 + square(t[2], t[1]) // hh + double(t[4], t[2]) + doubleAssign(t[4]) // 4hh + mul(t[5], t[1], t[4]) // j = h*i + subAssign(t[0], &p1[1]) // s2 - y1 + doubleAssign(t[0]) // r = 2*(s2 - y1) + square(t[6], t[0]) // r^2 + subAssign(t[6], t[5]) // r^2 - j + mul(t[3], &p1[0], t[4]) // v = x1 * i + double(t[4], t[3]) // 2*v + sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v + sub(t[4], t[3], &r[0]) // v - x3 + mul(t[6], &p1[1], t[5]) // y1 * j + doubleAssign(t[6]) // 2 * y1 * j + mul(t[0], t[0], t[4]) // r * (v - x3) + sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * y1 * j) + add(t[0], &p1[2], t[1]) // z1 + h + square(t[0], t[0]) // (z1 + h)^2 + subAssign(t[0], t[7]) // (z1 + h)^2 - z1z1 + sub(&r[2], t[0], t[2]) // z3 = (z1 + z2)^2 - z1z1 - hh + return r +} + +// Double doubles a G1 point p and assigns the result to the point at first argument. +func (g *G1) Double(r, p *PointG1) *PointG1 { + // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + if g.IsZero(p) { + return r.Zero() + } + t := g.t + square(t[0], &p[0]) // a = x^2 + square(t[1], &p[1]) // b = y^2 + square(t[2], t[1]) // c = b^2 + add(t[1], &p[0], t[1]) // b + x1 + square(t[1], t[1]) // (b + x1)^2 + subAssign(t[1], t[0]) // (b + x1)^2 - a + subAssign(t[1], t[2]) // (b + x1)^2 - a - c + doubleAssign(t[1]) // d = 2((b+x1)^2 - a - c) + double(t[3], t[0]) // 2a + addAssign(t[0], t[3]) // e = 3a + square(t[4], t[0]) // f = e^2 + double(t[3], t[1]) // 2d + sub(&r[0], t[4], t[3]) // x3 = f - 2d + subAssign(t[1], &r[0]) // d-x3 + doubleAssign(t[2]) // + doubleAssign(t[2]) // + doubleAssign(t[2]) // 8c + mul(t[0], t[0], t[1]) // e * (d - x3) + sub(t[1], t[0], t[2]) // x3 = e * (d - x3) - 8c + mul(t[0], &p[1], &p[2]) // y1 * z1 + r[1].set(t[1]) // + double(&r[2], t[0]) // z3 = 2(y1 * z1) + return r +} + +// Neg negates a G1 point p and assigns the result to the point at first argument. +func (g *G1) Neg(r, p *PointG1) *PointG1 { + r[0].set(&p[0]) + r[2].set(&p[2]) + neg(&r[1], &p[1]) + return r +} + +// Sub subtracts two G1 points p1, p2 and assigns the result to point at first argument. +func (g *G1) Sub(c, a, b *PointG1) *PointG1 { + d := &PointG1{} + g.Neg(d, b) + g.Add(c, a, d) + return c +} + +// MulScalar multiplies a point by given scalar value and assigns the result to point at first argument. +func (g *G1) MulScalar(r, p *PointG1, e *Fr) *PointG1 { + return g.glvMulFr(r, p, e) +} + +// MulScalar multiplies a point by given scalar value in big.Int and assigns the result to point at first argument. +func (g *G1) MulScalarBig(r, p *PointG1, e *big.Int) *PointG1 { + return g.glvMulBig(r, p, e) +} + +func (g *G1) mulScalar(c, p *PointG1, e *Fr) *PointG1 { + q, n := &PointG1{}, &PointG1{} + n.Set(p) + for i := 0; i < frBitSize; i++ { + if e.Bit(i) { + g.Add(q, q, n) + } + g.Double(n, n) + } + return c.Set(q) +} + +func (g *G1) mulScalarBig(c, p *PointG1, e *big.Int) *PointG1 { + q, n := &PointG1{}, &PointG1{} + n.Set(p) + for i := 0; i < frBitSize; i++ { + if e.Bit(i) == 1 { + g.Add(q, q, n) + } + g.Double(n, n) + } + return c.Set(q) +} + +func (g *G1) wnafMulFr(r, p *PointG1, e *Fr) *PointG1 { + wnaf := e.toWNAF(wnafMulWindowG1) + return g.wnafMul(r, p, wnaf) +} + +func (g *G1) wnafMulBig(r, p *PointG1, e *big.Int) *PointG1 { + wnaf := bigToWNAF(e, wnafMulWindowG1) + return g.wnafMul(r, p, wnaf) +} + +func (g *G1) wnafMul(c, p *PointG1, wnaf nafNumber) *PointG1 { + + l := (1 << (wnafMulWindowG1 - 1)) + + twoP, acc := g.New(), new(PointG1).Set(p) + g.Double(twoP, p) + g.Affine(twoP) + + // table = {p, 3p, 5p, ..., -p, -3p, -5p} + table := make([]*PointG1, l*2) + table[0], table[l] = g.New(), g.New() + table[0].Set(p) + g.Neg(table[l], table[0]) + + for i := 1; i < l; i++ { + g.AddMixed(acc, acc, twoP) + table[i], table[i+l] = g.New(), g.New() + table[i].Set(acc) + g.Neg(table[i+l], table[i]) + } + + q := g.Zero() + for i := len(wnaf) - 1; i >= 0; i-- { + if wnaf[i] > 0 { + g.Add(q, q, table[wnaf[i]>>1]) + } else if wnaf[i] < 0 { + g.Add(q, q, table[((-wnaf[i])>>1)+l]) + } + if i != 0 { + g.Double(q, q) + } + } + return c.Set(q) +} + +func (g *G1) glvMulFr(r, p *PointG1, e *Fr) *PointG1 { + return g.glvMul(r, p, new(glvVectorFr).new(e)) +} + +func (g *G1) glvMulBig(r, p *PointG1, e *big.Int) *PointG1 { + return g.glvMul(r, p, new(glvVectorBig).new(e)) +} + +func (g *G1) glvMul(r, p0 *PointG1, v glvVector) *PointG1 { + + w := glvMulWindowG1 + l := 1 << (w - 1) + + // prepare tables + // tableK1 = {P, 3P, 5P, ...} + // tableK2 = {λP, 3λP, 5λP, ...} + tableK1, tableK2 := make([]*PointG1, l), make([]*PointG1, l) + double := g.New() + g.Double(double, p0) + g.affine(double, double) + tableK1[0] = new(PointG1) + tableK1[0].Set(p0) + for i := 1; i < l; i++ { + tableK1[i] = new(PointG1) + g.AddMixed(tableK1[i], tableK1[i-1], double) + } + g.AffineBatch(tableK1) + for i := 0; i < l; i++ { + tableK2[i] = new(PointG1) + g.glvEndomorphism(tableK2[i], tableK1[i]) + } + + // recode small scalars + naf1, naf2 := v.wnaf(w) + lenNAF1, lenNAF2 := len(naf1), len(naf2) + lenNAF := lenNAF1 + if lenNAF2 > lenNAF { + lenNAF = lenNAF2 + } + + acc, p1 := g.New(), g.New() + + // function for naf addition + add := func(table []*PointG1, naf int) { + if naf != 0 { + nafAbs := naf + if nafAbs < 0 { + nafAbs = -nafAbs + } + p1.Set(table[nafAbs>>1]) + if naf < 0 { + g.Neg(p1, p1) + } + g.AddMixed(acc, acc, p1) + } + } + + // sliding + for i := lenNAF - 1; i >= 0; i-- { + if i < lenNAF1 { + add(tableK1, naf1[i]) + } + if i < lenNAF2 { + add(tableK2, naf2[i]) + } + if i != 0 { + g.Double(acc, acc) + } + } + return r.Set(acc) +} + +// MultiExpBig calculates multi exponentiation. Scalar values are received as big.Int type. +// Given pairs of G1 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`, +// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`. +// Length of points and scalars are expected to be equal, otherwise an error is returned. +// Result is assigned to point at first argument. +func (g *G1) MultiExpBig(r *PointG1, points []*PointG1, scalars []*big.Int) (*PointG1, error) { + if len(points) != len(scalars) { + return nil, errors.New("point and scalar vectors should be in same length") + } + + c := 3 + if len(scalars) >= 32 { + c = int(math.Ceil(math.Log(float64(len(scalars))))) + } + + bucketSize := (1 << c) - 1 + windows := make([]PointG1, 255/c+1) + bucket := make([]PointG1, bucketSize) + + for j := 0; j < len(windows); j++ { + + for i := 0; i < bucketSize; i++ { + bucket[i].Zero() + } + + for i := 0; i < len(scalars); i++ { + index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(c*j)).Int64()) + if index != 0 { + g.Add(&bucket[index-1], &bucket[index-1], points[i]) + } + } + + acc, sum := g.New(), g.New() + for i := bucketSize - 1; i >= 0; i-- { + g.Add(sum, sum, &bucket[i]) + g.Add(acc, acc, sum) + } + windows[j].Set(acc) + } + + acc := g.New() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < c; j++ { + g.Double(acc, acc) + } + g.Add(acc, acc, &windows[i]) + } + return r.Set(acc), nil +} + +// MultiExp calculates multi exponentiation. Given pairs of G1 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`, +// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`. Length of points and scalars are expected to be equal, +// otherwise an error is returned. Result is assigned to point at first argument. +func (g *G1) MultiExp(r *PointG1, points []*PointG1, scalars []*Fr) (*PointG1, error) { + if len(points) != len(scalars) { + return nil, errors.New("point and scalar vectors should be in same length") + } + + g.AffineBatch(points) + + c := 3 + if len(scalars) >= 32 { + c = int(math.Ceil(math.Log(float64(len(scalars))))) + } + + bucketSize := (1 << c) - 1 + windows := make([]*PointG1, 255/c+1) + bucket := make([]PointG1, bucketSize) + + for j := 0; j < len(windows); j++ { + + for i := 0; i < bucketSize; i++ { + bucket[i].Zero() + } + + for i := 0; i < len(scalars); i++ { + index := bucketSize & int(scalars[i].sliceUint64(c*j)) + if index != 0 { + g.AddMixed(&bucket[index-1], &bucket[index-1], points[i]) + } + } + + acc, sum := g.New(), g.New() + for i := bucketSize - 1; i >= 0; i-- { + g.Add(sum, sum, &bucket[i]) + g.Add(acc, acc, sum) + } + windows[j] = g.New().Set(acc) + } + + g.AffineBatch(windows) + + acc := g.New() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < c; j++ { + g.Double(acc, acc) + } + g.AddMixed(acc, acc, windows[i]) + } + return r.Set(acc), nil +} + +func (g *G1) ClearCofactor(p *PointG1) *PointG1 { + chain := func(p0 *PointG1, n int, p1 *PointG1) { + for i := 0; i < n; i++ { + g.Double(p0, p0) + } + g.Add(p0, p0, p1) + } + t := g.New().Set(p) + chain(p, 1, t) + chain(p, 2, t) + chain(p, 3, t) + chain(p, 9, t) + chain(p, 32, t) + chain(p, 16, t) + return p +} + +// MapToCurve given a byte slice returns a valid G1 point. +// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06 +// Input byte slice should be a valid field element, otherwise an error is returned. +func (g *G1) MapToCurve(in []byte) (*PointG1, error) { + u, err := fromBytes(in) + if err != nil { + return nil, err + } + x, y := swuMapG1(u) + isogenyMapG1(x, y) + one := new(fe).one() + p := &PointG1{*x, *y, *one} + g.ClearCofactor(p) + return g.Affine(p), nil +} + +// EncodeToCurve given a message and domain seperator tag returns the hash result +// which is a valid curve point. +// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06 +func (g *G1) EncodeToCurve(msg, domain []byte) (*PointG1, error) { + hashRes, err := hashToFpXMDSHA256(msg, domain, 1) + if err != nil { + return nil, err + } + u := hashRes[0] + x, y := swuMapG1(u) + isogenyMapG1(x, y) + one := new(fe).one() + p := &PointG1{*x, *y, *one} + g.ClearCofactor(p) + return g.Affine(p), nil +} + +// HashToCurve given a message and domain seperator tag returns the hash result +// which is a valid curve point. +// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06 +func (g *G1) HashToCurve(msg, domain []byte) (*PointG1, error) { + hashRes, err := hashToFpXMDSHA256(msg, domain, 2) + if err != nil { + return nil, err + } + u0, u1 := hashRes[0], hashRes[1] + x0, y0 := swuMapG1(u0) + x1, y1 := swuMapG1(u1) + one := new(fe).one() + p0, p1 := &PointG1{*x0, *y0, *one}, &PointG1{*x1, *y1, *one} + g.Add(p0, p0, p1) + g.Affine(p0) + isogenyMapG1(&p0[0], &p0[1]) + g.ClearCofactor(p0) + return g.Affine(p0), nil +} diff --git a/vendor/github.com/kilic/bls12-381/g2.go b/vendor/github.com/kilic/bls12-381/g2.go new file mode 100644 index 00000000000..5eae0fa0d34 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/g2.go @@ -0,0 +1,889 @@ +package bls12381 + +import ( + "errors" + "math" + "math/big" +) + +// PointG2 is type for point in G2 and used for both affine and Jacobian representation. +// A point is accounted as in affine form if z is equal to one. +type PointG2 [3]fe2 + +var wnafMulWindowG2 uint = 6 + +// Set copies valeus of one point to another. +func (p *PointG2) Set(p2 *PointG2) *PointG2 { + p[0].set(&p2[0]) + p[1].set(&p2[1]) + p[2].set(&p2[2]) + return p +} + +func (p *PointG2) Zero() *PointG2 { + p[0].zero() + p[1].one() + p[2].zero() + return p +} + +// IsAffine checks a G1 point whether it is in affine form. +func (p *PointG2) IsAffine() bool { + return p[2].isOne() +} + +type tempG2 struct { + t [9]*fe2 +} + +// G2 is struct for G2 group. +type G2 struct { + f *fp2 + tempG2 +} + +// NewG2 constructs a new G2 instance. +func NewG2() *G2 { + return newG2(nil) +} + +func newG2(f *fp2) *G2 { + if f == nil { + f = newFp2() + } + t := newTempG2() + return &G2{f, t} +} + +func newTempG2() tempG2 { + t := [9]*fe2{} + for i := 0; i < 9; i++ { + t[i] = &fe2{} + } + return tempG2{t} +} + +// Q returns group order in big.Int. +func (g *G2) Q() *big.Int { + return new(big.Int).Set(qBig) +} + +// FromUncompressed expects byte slice at least 192 bytes and given bytes returns a new point in G2. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G2) FromUncompressed(uncompressed []byte) (*PointG2, error) { + if len(uncompressed) != 4*fpByteSize { + return nil, errors.New("input string length must be equal to 192 bytes") + } + var in [4 * fpByteSize]byte + copy(in[:], uncompressed[:4*fpByteSize]) + if in[0]&(1<<7) != 0 { + return nil, errors.New("compression flag must be zero") + } + if in[0]&(1<<5) != 0 { + return nil, errors.New("sort flag must be zero") + } + if in[0]&(1<<6) != 0 { + for i, v := range in { + if (i == 0 && v != 0x40) || (i != 0 && v != 0x00) { + return nil, errors.New("input string must be zero when infinity flag is set") + } + } + return g.Zero(), nil + } + in[0] &= 0x1f + x, err := g.f.fromBytes(in[:2*fpByteSize]) + if err != nil { + return nil, err + } + y, err := g.f.fromBytes(in[2*fpByteSize:]) + if err != nil { + return nil, err + } + z := new(fe2).one() + p := &PointG2{*x, *y, *z} + if !g.IsOnCurve(p) { + return nil, errors.New("point is not on curve") + } + if !g.InCorrectSubgroup(p) { + return nil, errors.New("point is not on correct subgroup") + } + return p, nil +} + +// ToUncompressed given a G2 point returns bytes in uncompressed (x, y) form of the point. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G2) ToUncompressed(p *PointG2) []byte { + out := make([]byte, 4*fpByteSize) + g.Affine(p) + if g.IsZero(p) { + out[0] |= 1 << 6 + return out + } + copy(out[:2*fpByteSize], g.f.toBytes(&p[0])) + copy(out[2*fpByteSize:], g.f.toBytes(&p[1])) + return out +} + +// FromCompressed expects byte slice at least 96 bytes and given bytes returns a new point in G2. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G2) FromCompressed(compressed []byte) (*PointG2, error) { + if len(compressed) != 2*fpByteSize { + return nil, errors.New("input string length must be equal to 96 bytes") + } + var in [2 * fpByteSize]byte + copy(in[:], compressed[:]) + if in[0]&(1<<7) == 0 { + return nil, errors.New("compression flag must be set") + } + if in[0]&(1<<6) != 0 { + // in[0] == (1 << 6) + (1 << 7) + for i, v := range in { + if (i == 0 && v != 0xc0) || (i != 0 && v != 0x00) { + return nil, errors.New("input string must be zero when infinity flag is set") + } + } + return g.Zero(), nil + } + a := in[0]&(1<<5) != 0 + in[0] &= 0x1f + x, err := g.f.fromBytes(in[:]) + if err != nil { + return nil, err + } + // solve curve equation + y := &fe2{} + g.f.square(y, x) + g.f.mul(y, y, x) + g.f.add(y, y, b2) + if ok := g.f.sqrt(y, y); !ok { + return nil, errors.New("point is not on curve") + } + if y.signBE() == a { + g.f.neg(y, y) + } + z := new(fe2).one() + p := &PointG2{*x, *y, *z} + if !g.InCorrectSubgroup(p) { + return nil, errors.New("point is not on correct subgroup") + } + return p, nil +} + +// ToCompressed given a G2 point returns bytes in compressed form of the point. +// Serialization rules are in line with zcash library. See below for details. +// https://github.com/zcash/librustzcash/blob/master/pairing/src/bls12_381/README.md#serialization +// https://docs.rs/bls12_381/0.1.1/bls12_381/notes/serialization/index.html +func (g *G2) ToCompressed(p *PointG2) []byte { + out := make([]byte, 2*fpByteSize) + g.Affine(p) + if g.IsZero(p) { + out[0] |= 1 << 6 + } else { + copy(out[:], g.f.toBytes(&p[0])) + if !p[1].signBE() { + out[0] |= 1 << 5 + } + } + out[0] |= 1 << 7 + return out +} + +func (g *G2) fromBytesUnchecked(in []byte) (*PointG2, error) { + p0, err := g.f.fromBytes(in[:2*fpByteSize]) + if err != nil { + return nil, err + } + p1, err := g.f.fromBytes(in[2*fpByteSize:]) + if err != nil { + return nil, err + } + p2 := new(fe2).one() + return &PointG2{*p0, *p1, *p2}, nil +} + +// FromBytes constructs a new point given uncompressed byte input. +// Input string expected to be 192 bytes and concatenation of x and y values +// Point (0, 0) is considered as infinity. +func (g *G2) FromBytes(in []byte) (*PointG2, error) { + if len(in) != 4*fpByteSize { + return nil, errors.New("input string length must be equal to 192 bytes") + } + p0, err := g.f.fromBytes(in[:2*fpByteSize]) + if err != nil { + return nil, err + } + p1, err := g.f.fromBytes(in[2*fpByteSize:]) + if err != nil { + return nil, err + } + // check if given input points to infinity + if p0.isZero() && p1.isZero() { + return g.Zero(), nil + } + p2 := new(fe2).one() + p := &PointG2{*p0, *p1, *p2} + if !g.IsOnCurve(p) { + return nil, errors.New("point is not on curve") + } + return p, nil +} + +// ToBytes serializes a point into bytes in uncompressed form, +// returns (0, 0) if point is infinity. +func (g *G2) ToBytes(p *PointG2) []byte { + out := make([]byte, 4*fpByteSize) + if g.IsZero(p) { + return out + } + g.Affine(p) + copy(out[:2*fpByteSize], g.f.toBytes(&p[0])) + copy(out[2*fpByteSize:], g.f.toBytes(&p[1])) + return out +} + +// New creates a new G2 Point which is equal to zero in other words point at infinity. +func (g *G2) New() *PointG2 { + return new(PointG2).Zero() +} + +// Zero returns a new G2 Point which is equal to point at infinity. +func (g *G2) Zero() *PointG2 { + return new(PointG2).Zero() +} + +// One returns a new G2 Point which is equal to generator point. +func (g *G2) One() *PointG2 { + p := &PointG2{} + return p.Set(&g2One) +} + +// IsZero returns true if given point is equal to zero. +func (g *G2) IsZero(p *PointG2) bool { + return p[2].isZero() +} + +// Equal checks if given two G2 point is equal in their affine form. +func (g *G2) Equal(p1, p2 *PointG2) bool { + if g.IsZero(p1) { + return g.IsZero(p2) + } + if g.IsZero(p2) { + return g.IsZero(p1) + } + t := g.t + g.f.square(t[0], &p1[2]) + g.f.square(t[1], &p2[2]) + g.f.mul(t[2], t[0], &p2[0]) + g.f.mul(t[3], t[1], &p1[0]) + g.f.mulAssign(t[0], &p1[2]) + g.f.mulAssign(t[1], &p2[2]) + g.f.mulAssign(t[1], &p1[1]) + g.f.mulAssign(t[0], &p2[1]) + return t[0].equal(t[1]) && t[2].equal(t[3]) +} + +// IsOnCurve checks a G2 point is on curve. +func (g *G2) IsOnCurve(p *PointG2) bool { + if g.IsZero(p) { + return true + } + t := g.t + g.f.square(t[0], &p[1]) // y^2 + g.f.square(t[1], &p[0]) // x^2 + g.f.mul(t[1], t[1], &p[0]) // x^3 + if p.IsAffine() { + g.f.add(t[1], t[1], b2) // x^2 + b + return t[0].equal(t[1]) // y^2 ?= x^3 + b + } + g.f.square(t[2], &p[2]) // z^2 + g.f.square(t[3], t[2]) // z^4 + g.f.mulAssign(t[2], t[3]) // z^6 + g.f.mulAssign(t[2], b2) // b*z^6 + g.f.addAssign(t[1], t[2]) // x^3 + b * z^6 + return t[0].equal(t[1]) // y^2 ?= x^3 + b * z^6 +} + +// IsAffine checks a G2 point whether it is in affine form. +func (g *G2) IsAffine(p *PointG2) bool { + return p[2].isOne() +} + +// Affine calculates affine form of given G2 point. +func (g *G2) Affine(p *PointG2) *PointG2 { + return g.affine(p, p) +} + +func (g *G2) affine(r, p *PointG2) *PointG2 { + if g.IsZero(p) { + return r.Zero() + } + if !g.IsAffine(p) { + t := g.t + g.f.inverse(t[0], &p[2]) // z^-1 + g.f.square(t[1], t[0]) // z^-2 + g.f.mulAssign(&r[0], t[1]) // x = x * z^-2 + g.f.mulAssign(t[0], t[1]) // z^-3 + g.f.mulAssign(&r[1], t[0]) // y = y * z^-3 + r[2].one() // z = 1 + } else { + r.Set(p) + } + return r +} + +// AffineBatch given multiple of points returns affine representations +func (g *G2) AffineBatch(p []*PointG2) { + inverses := make([]fe2, len(p)) + for i := 0; i < len(p); i++ { + inverses[i].set(&p[i][2]) + } + g.f.inverseBatch(inverses) + t := g.t + for i := 0; i < len(p); i++ { + if !g.IsAffine(p[i]) && !g.IsZero(p[i]) { + g.f.square(t[1], &inverses[i]) + g.f.mulAssign(&p[i][0], t[1]) + g.f.mul(t[0], &inverses[i], t[1]) + g.f.mulAssign(&p[i][1], t[0]) + p[i][2].one() + } + } +} + +// Add adds two G2 points p1, p2 and assigns the result to point at first argument. +func (g *G2) Add(r, p1, p2 *PointG2) *PointG2 { + // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#addition-add-2007-bl + if g.IsZero(p1) { + return r.Set(p2) + } + if g.IsZero(p2) { + return r.Set(p1) + } + if g.IsAffine(p2) { + return g.AddMixed(r, p1, p2) + } + t := g.t + g.f.square(t[7], &p1[2]) // z1z1 + g.f.mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1 + g.f.mul(t[2], &p1[2], t[7]) // z1z1 * z1 + g.f.mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1 + g.f.square(t[8], &p2[2]) // z2z2 + g.f.mul(t[3], &p1[0], t[8]) // u1 = x1 * z2z2 + g.f.mul(t[4], &p2[2], t[8]) // z2z2 * z2 + g.f.mul(t[2], &p1[1], t[4]) // s1 = y1 * z2z2 * z2 + if t[1].equal(t[3]) { + if t[0].equal(t[2]) { + return g.Double(r, p1) + } else { + return r.Zero() + } + } + g.f.subAssign(t[1], t[3]) // h = u2 - u1 + g.f.double(t[4], t[1]) // 2h + g.f.squareAssign(t[4]) // i = 2h^2 + g.f.mul(t[5], t[1], t[4]) // j = h*i + g.f.subAssign(t[0], t[2]) // s2 - s1 + g.f.doubleAssign(t[0]) // r = 2*(s2 - s1) + g.f.square(t[6], t[0]) // r^2 + g.f.subAssign(t[6], t[5]) // r^2 - j + g.f.mulAssign(t[3], t[4]) // v = u1 * i + g.f.double(t[4], t[3]) // 2*v + g.f.sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v + g.f.sub(t[4], t[3], &r[0]) // v - x3 + g.f.mul(t[6], t[2], t[5]) // s1 * j + g.f.doubleAssign(t[6]) // 2 * s1 * j + g.f.mulAssign(t[0], t[4]) // r * (v - x3) + g.f.sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * s1 * j) + g.f.add(t[0], &p1[2], &p2[2]) // z1 + z2 + g.f.squareAssign(t[0]) // (z1 + z2)^2 + g.f.subAssign(t[0], t[7]) // (z1 + z2)^2 - z1z1 + g.f.subAssign(t[0], t[8]) // (z1 + z2)^2 - z1z1 - z2z2 + g.f.mul(&r[2], t[0], t[1]) // z3 = ((z1 + z2)^2 - z1z1 - z2z2) * h + return r +} + +// Add adds two G1 points p1, p2 and assigns the result to point at first argument. +// Expects the second point p2 in affine form. +func (g *G2) AddMixed(r, p1, p2 *PointG2) *PointG2 { + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl + if g.IsZero(p1) { + return r.Set(p2) + } + if g.IsZero(p2) { + return r.Set(p1) + } + t := g.t + g.f.square(t[7], &p1[2]) // z1z1 + g.f.mul(t[1], &p2[0], t[7]) // u2 = x2 * z1z1 + g.f.mul(t[2], &p1[2], t[7]) // z1z1 * z1 + g.f.mul(t[0], &p2[1], t[2]) // s2 = y2 * z1z1 * z1 + + if p1[0].equal(t[1]) && p1[1].equal(t[0]) { + return g.Double(r, p1) + } + + g.f.sub(t[1], t[1], &p1[0]) // h = u2 - x1 + g.f.square(t[2], t[1]) // hh + g.f.double(t[4], t[2]) + g.f.doubleAssign(t[4]) // 4hh + g.f.mul(t[5], t[1], t[4]) // j = h*i + g.f.subAssign(t[0], &p1[1]) // s2 - y1 + g.f.doubleAssign(t[0]) // r = 2*(s2 - y1) + g.f.square(t[6], t[0]) // r^2 + g.f.subAssign(t[6], t[5]) // r^2 - j + g.f.mul(t[3], &p1[0], t[4]) // v = x1 * i + g.f.double(t[4], t[3]) // 2*v + g.f.sub(&r[0], t[6], t[4]) // x3 = r^2 - j - 2*v + g.f.sub(t[4], t[3], &r[0]) // v - x3 + g.f.mul(t[6], &p1[1], t[5]) // y1 * j + g.f.doubleAssign(t[6]) // 2 * y1 * j + g.f.mulAssign(t[0], t[4]) // r * (v - x3) + g.f.sub(&r[1], t[0], t[6]) // y3 = r * (v - x3) - (2 * y1 * j) + g.f.add(t[0], &p1[2], t[1]) // z1 + h + g.f.squareAssign(t[0]) // (z1 + h)^2 + g.f.subAssign(t[0], t[7]) // (z1 + h)^2 - z1z1 + g.f.sub(&r[2], t[0], t[2]) // z3 = (z1 + z2)^2 - z1z1 - hh + return r +} + +// Double doubles a G2 point p and assigns the result to the point at first argument. +func (g *G2) Double(r, p *PointG2) *PointG2 { + // http://www.hyperelliptic.org/EFD/gp/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + if g.IsZero(p) { + return r.Set(p) + } + t := g.t + g.f.square(t[0], &p[0]) // a = x^2 + g.f.square(t[1], &p[1]) // b = y^2 + g.f.square(t[2], t[1]) // c = b^2 + g.f.addAssign(t[1], &p[0]) // b + x1 + g.f.squareAssign(t[1]) // (b + x1)^2 + g.f.subAssign(t[1], t[0]) // (b + x1)^2 - a + g.f.subAssign(t[1], t[2]) // (b + x1)^2 - a - c + g.f.doubleAssign(t[1]) // d = 2((b+x1)^2 - a - c) + g.f.double(t[3], t[0]) // 2a + g.f.addAssign(t[0], t[3]) // e = 3a + g.f.square(t[4], t[0]) // f = e^2 + g.f.double(t[3], t[1]) // 2d + g.f.sub(&r[0], t[4], t[3]) // x3 = f - 2d + g.f.sub(t[1], t[1], &r[0]) // d-x3 + g.f.doubleAssign(t[2]) // + g.f.doubleAssign(t[2]) // + g.f.doubleAssign(t[2]) // 8c + g.f.mulAssign(t[0], t[1]) // e * (d - x3) + g.f.sub(t[1], t[0], t[2]) // x3 = e * (d - x3) - 8c + g.f.mul(t[0], &p[1], &p[2]) // y1 * z1 + r[1].set(t[1]) // + g.f.double(&r[2], t[0]) // z3 = 2(y1 * z1) + return r +} + +// Neg negates a G2 point p and assigns the result to the point at first argument. +func (g *G2) Neg(r, p *PointG2) *PointG2 { + r[0].set(&p[0]) + g.f.neg(&r[1], &p[1]) + r[2].set(&p[2]) + return r +} + +// Sub subtracts two G2 points p1, p2 and assigns the result to point at first argument. +func (g *G2) Sub(c, a, b *PointG2) *PointG2 { + d := &PointG2{} + g.Neg(d, b) + g.Add(c, a, d) + return c +} + +// MulScalar multiplies a point by given scalar value and assigns the result to point at first argument. +func (g *G2) MulScalar(r, p *PointG2, e *Fr) *PointG2 { + return g.glvMulFr(r, p, e) +} + +// MulScalarBig multiplies a point by given scalar value in big.Int and assigns the result to point at first argument. +func (g *G2) MulScalarBig(r, p *PointG2, e *big.Int) *PointG2 { + return g.glvMulBig(r, p, e) +} + +func (g *G2) mulScalar(c, p *PointG2, e *Fr) *PointG2 { + q, n := &PointG2{}, &PointG2{} + n.Set(p) + for i := 0; i < frBitSize; i++ { + if e.Bit(i) { + g.Add(q, q, n) + } + g.Double(n, n) + } + return c.Set(q) +} + +func (g *G2) mulScalarBig(c, p *PointG2, e *big.Int) *PointG2 { + q, n := &PointG2{}, &PointG2{} + n.Set(p) + l := e.BitLen() + for i := 0; i < l; i++ { + if e.Bit(i) == 1 { + g.Add(q, q, n) + } + g.Double(n, n) + } + return c.Set(q) +} + +func (g *G2) wnafMulFr(r, p *PointG2, e *Fr) *PointG2 { + wnaf := e.toWNAF(wnafMulWindowG2) + return g.wnafMul(r, p, wnaf) +} + +func (g *G2) wnafMulBig(r, p *PointG2, e *big.Int) *PointG2 { + wnaf := bigToWNAF(e, wnafMulWindowG2) + return g.wnafMul(r, p, wnaf) +} + +func (g *G2) wnafMul(c, p *PointG2, wnaf nafNumber) *PointG2 { + + l := (1 << (wnafMulWindowG2 - 1)) + + twoP, acc := g.New(), new(PointG2).Set(p) + g.Double(twoP, p) + g.Affine(twoP) + + // table = {p, 3p, 5p, ..., -p, -3p, -5p} + table := make([]*PointG2, l*2) + table[0], table[l] = g.New(), g.New() + table[0].Set(p) + g.Neg(table[l], table[0]) + + for i := 1; i < l; i++ { + g.AddMixed(acc, acc, twoP) + table[i], table[i+l] = g.New(), g.New() + table[i].Set(acc) + g.Neg(table[i+l], table[i]) + } + + q := g.Zero() + for i := len(wnaf) - 1; i >= 0; i-- { + if wnaf[i] > 0 { + g.Add(q, q, table[wnaf[i]>>1]) + } else if wnaf[i] < 0 { + g.Add(q, q, table[((-wnaf[i])>>1)+l]) + } + if i != 0 { + g.Double(q, q) + } + } + return c.Set(q) +} + +func (g *G2) glvMulFr(r, p *PointG2, e *Fr) *PointG2 { + return g.glvMul(r, p, new(glvVectorFr).new(e)) +} + +func (g *G2) glvMulBig(r, p *PointG2, e *big.Int) *PointG2 { + return g.glvMul(r, p, new(glvVectorBig).new(e)) +} + +func (g *G2) glvMul(r, p0 *PointG2, v glvVector) *PointG2 { + + w := glvMulWindowG2 + l := 1 << (w - 1) + + // prepare tables + // tableK1 = {P, 3P, 5P, ...} + // tableK2 = {λP, 3λP, 5λP, ...} + tableK1, tableK2 := make([]*PointG2, l), make([]*PointG2, l) + double := g.New() + g.Double(double, p0) + g.affine(double, double) + tableK1[0] = new(PointG2) + tableK1[0].Set(p0) + for i := 1; i < l; i++ { + tableK1[i] = new(PointG2) + g.AddMixed(tableK1[i], tableK1[i-1], double) + } + g.AffineBatch(tableK1) + for i := 0; i < l; i++ { + tableK2[i] = new(PointG2) + g.glvEndomorphism(tableK2[i], tableK1[i]) + } + + // recode small scalars + naf1, naf2 := v.wnaf(w) + lenNAF1, lenNAF2 := len(naf1), len(naf2) + lenNAF := lenNAF1 + if lenNAF2 > lenNAF { + lenNAF = lenNAF2 + } + + acc, p1 := g.New(), g.New() + + // function for naf addition + add := func(table []*PointG2, naf int) { + if naf != 0 { + nafAbs := naf + if nafAbs < 0 { + nafAbs = -nafAbs + } + p1.Set(table[nafAbs>>1]) + if naf < 0 { + g.Neg(p1, p1) + } + g.AddMixed(acc, acc, p1) + } + } + + // sliding + for i := lenNAF - 1; i >= 0; i-- { + if i < lenNAF1 { + add(tableK1, naf1[i]) + } + if i < lenNAF2 { + add(tableK2, naf2[i]) + } + if i != 0 { + g.Double(acc, acc) + } + } + return r.Set(acc) +} + +// MultiExpBig calculates multi exponentiation. Scalar values are received as big.Int type. +// Given pairs of G2 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`, +// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`. +// Length of points and scalars are expected to be equal, otherwise an error is returned. +// Result is assigned to point at first argument. +func (g *G2) MultiExpBig(r *PointG2, points []*PointG2, scalars []*big.Int) (*PointG2, error) { + if len(points) != len(scalars) { + return nil, errors.New("point and scalar vectors should be in same length") + } + + c := 3 + if len(scalars) >= 32 { + c = int(math.Ceil(math.Log(float64(len(scalars))))) + } + + bucketSize := (1 << c) - 1 + windows := make([]PointG2, 255/c+1) + bucket := make([]PointG2, bucketSize) + + for j := 0; j < len(windows); j++ { + + for i := 0; i < bucketSize; i++ { + bucket[i].Zero() + } + + for i := 0; i < len(scalars); i++ { + index := bucketSize & int(new(big.Int).Rsh(scalars[i], uint(c*j)).Int64()) + if index != 0 { + g.Add(&bucket[index-1], &bucket[index-1], points[i]) + } + } + + acc, sum := g.New(), g.New() + for i := bucketSize - 1; i >= 0; i-- { + g.Add(sum, sum, &bucket[i]) + g.Add(acc, acc, sum) + } + windows[j].Set(acc) + } + + acc := g.New() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < c; j++ { + g.Double(acc, acc) + } + g.Add(acc, acc, &windows[i]) + } + return r.Set(acc), nil +} + +// MultiExp calculates multi exponentiation. Given pairs of G2 point and scalar values `(P_0, e_0), (P_1, e_1), ... (P_n, e_n)`, +// calculates `r = e_0 * P_0 + e_1 * P_1 + ... + e_n * P_n`. Length of points and scalars are expected to be equal, +// otherwise an error is returned. Result is assigned to point at first argument. +func (g *G2) MultiExp(r *PointG2, points []*PointG2, scalars []*Fr) (*PointG2, error) { + if len(points) != len(scalars) { + return nil, errors.New("point and scalar vectors should be in same length") + } + + g.AffineBatch(points) + + c := 3 + if len(scalars) >= 32 { + c = int(math.Ceil(math.Log(float64(len(scalars))))) + } + + bucketSize := (1 << c) - 1 + windows := make([]*PointG2, 255/c+1) + bucket := make([]PointG2, bucketSize) + + for j := 0; j < len(windows); j++ { + + for i := 0; i < bucketSize; i++ { + bucket[i].Zero() + } + + for i := 0; i < len(scalars); i++ { + index := bucketSize & int(scalars[i].sliceUint64(c*j)) + if index != 0 { + g.AddMixed(&bucket[index-1], &bucket[index-1], points[i]) + } + } + + acc, sum := g.New(), g.New() + for i := bucketSize - 1; i >= 0; i-- { + g.Add(sum, sum, &bucket[i]) + g.Add(acc, acc, sum) + } + windows[j] = g.New().Set(acc) + } + + g.AffineBatch(windows) + + acc := g.New() + for i := len(windows) - 1; i >= 0; i-- { + for j := 0; j < c; j++ { + g.Double(acc, acc) + } + g.AddMixed(acc, acc, windows[i]) + } + return r.Set(acc), nil +} + +// InCorrectSubgroup checks whether given point is in correct subgroup. +func (g *G2) InCorrectSubgroup(p *PointG2) bool { + + // Faster Subgroup Checks for BLS12-381 + // S. Bowe + // https://eprint.iacr.org/2019/814.pdf + + // [z]ψ^3(P) − ψ^2(P) + P = O + t0, t1 := g.New().Set(p), g.New() + + g.psi(t0) + g.psi(t0) + g.Neg(t1, t0) // - ψ^2(P) + g.psi(t0) // ψ^3(P) + g.mulX(t0) // - x ψ^3(P) + g.Neg(t0, t0) + + g.Add(t0, t0, t1) + g.Add(t0, t0, p) + + return g.IsZero(t0) +} + +// ClearCofactor maps given a G2 point to correct subgroup +func (g *G2) ClearCofactor(p *PointG2) *PointG2 { + + // Efficient hash maps to G2 on BLS curves + // A. Budroni, F. Pintore + // https://eprint.iacr.org/2017/419.pdf + + // [h(ψ)]P = [x^2 − x − 1]P + [x − 1]ψ(P) + ψ^2(2P) + t0, t1, t2, t3 := g.New().Set(p), g.New().Set(p), g.New().Set(p), g.New() + + g.Double(t0, t0) + g.psi(t0) + g.psi(t0) // P2 = ψ^2(2P) + g.psi(t2) // P1 = ψ(P) + g.mulX(t1) // -xP0 + + g.Sub(t3, t1, t2) // -xP0 - P1 + g.mulX(t3) // (x^2)P0 + xP1 + g.Sub(t1, t1, p) // (-x-1)P0 + g.Add(t3, t3, t1) // (x^2-x-1)P0 + xP1 + g.Sub(t3, t3, t2) // (x^2-x-1)P0 + (x-1)P1 + g.Add(t3, t3, t0) // (x^2-x-1)P0 + (x-1)P1 + P2 + return p.Set(t3) +} + +func (g *G2) psi(p *PointG2) { + g.f.conjugate(&p[0], &p[0]) + g.f.conjugate(&p[1], &p[1]) + g.f.conjugate(&p[2], &p[2]) + g.f.mul(&p[0], &p[0], &psix) + g.f.mul(&p[1], &p[1], &psiy) +} + +func (g *G2) mulX(p *PointG2) { + + chain := func(p0 *PointG2, n int, p1 *PointG2) { + g.Add(p0, p0, p1) + for i := 0; i < n; i++ { + g.Double(p0, p0) + } + } + + t := g.New().Set(p) + g.Double(p, t) + chain(p, 2, t) + chain(p, 3, t) + chain(p, 9, t) + chain(p, 32, t) + chain(p, 16, t) +} + +// MapToCurve given a byte slice returns a valid G2 point. +// This mapping function implements the Simplified Shallue-van de Woestijne-Ulas method. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-05#section-6.6.2 +// Input byte slice should be a valid field element, otherwise an error is returned. +func (g *G2) MapToCurve(in []byte) (*PointG2, error) { + fp2 := g.f + u, err := fp2.fromBytes(in) + if err != nil { + return nil, err + } + x, y := swuMapG2(fp2, u) + isogenyMapG2(fp2, x, y) + z := new(fe2).one() + q := &PointG2{*x, *y, *z} + g.ClearCofactor(q) + return g.Affine(q), nil +} + +// EncodeToCurve given a message and domain seperator tag returns the hash result +// which is a valid curve point. +// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_NU_ suite at +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06 +func (g *G2) EncodeToCurve(msg, domain []byte) (*PointG2, error) { + hashRes, err := hashToFpXMDSHA256(msg, domain, 2) + if err != nil { + return nil, err + } + fp2 := g.f + u := &fe2{*hashRes[0], *hashRes[1]} + x, y := swuMapG2(fp2, u) + isogenyMapG2(fp2, x, y) + z := new(fe2).one() + q := &PointG2{*x, *y, *z} + g.ClearCofactor(q) + return g.Affine(q), nil +} + +// HashToCurve given a message and domain seperator tag returns the hash result +// which is a valid curve point. +// Implementation follows BLS12381G1_XMD:SHA-256_SSWU_RO_ suite at +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06 +func (g *G2) HashToCurve(msg, domain []byte) (*PointG2, error) { + hashRes, err := hashToFpXMDSHA256(msg, domain, 4) + if err != nil { + return nil, err + } + fp2 := g.f + u0, u1 := &fe2{*hashRes[0], *hashRes[1]}, &fe2{*hashRes[2], *hashRes[3]} + x0, y0 := swuMapG2(fp2, u0) + x1, y1 := swuMapG2(fp2, u1) + z0 := new(fe2).one() + z1 := new(fe2).one() + p0, p1 := &PointG2{*x0, *y0, *z0}, &PointG2{*x1, *y1, *z1} + g.Add(p0, p0, p1) + g.Affine(p0) + isogenyMapG2(fp2, &p0[0], &p0[1]) + g.ClearCofactor(p0) + return g.Affine(p0), nil +} diff --git a/vendor/github.com/kilic/bls12-381/glv.go b/vendor/github.com/kilic/bls12-381/glv.go new file mode 100644 index 00000000000..0e618189280 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/glv.go @@ -0,0 +1,200 @@ +package bls12381 + +import ( + "math/big" +) + +// Guide to Pairing Based Cryptography +// 6.3.2. Decompositions for the k = 12 BLS Family + +// glvQ1 = x^2 * R / q +var glvQ1 = &Fr{0x63f6e522f6cfee30, 0x7c6becf1e01faadd, 0x1, 0} +var glvQ1Big = bigFromHex("0x017c6becf1e01faadd63f6e522f6cfee30") + +// glvQ2 = R / q = 2 +var glvQ2 = &Fr{0x02, 0, 0, 0} +var glvQ2Big = bigFromHex("0x02") + +// glvB1 = x^2 - 1 = 0xac45a4010001a40200000000ffffffff +var glvB1 = &Fr{0x00000000ffffffff, 0xac45a4010001a402, 0, 0} +var glvB1Big = bigFromHex("0xac45a4010001a40200000000ffffffff") + +// glvB2 = x^2 = 0xac45a4010001a4020000000100000000 +var glvB2 = &Fr{0x0000000100000000, 0xac45a4010001a402, 0, 0} +var glvB2Big = bigFromHex("0xac45a4010001a4020000000100000000") + +// glvLambdaA = x^2 - 1 +var glvLambda = &Fr{0x00000000ffffffff, 0xac45a4010001a402, 0, 0} +var glvLambdaBig = bigFromHex("0xac45a4010001a40200000000ffffffff") + +// halfR = 2**256 / 2 +var halfR = &wideFr{0, 0, 0, 0x8000000000000000, 0, 0, 0} +var halfRBig = bigFromHex("0x8000000000000000000000000000000000000000000000000000000000000000") + +// r128 = 2**128 - 1 +var r128 = &Fr{0xffffffffffffffff, 0xffffffffffffffff, 0, 0} + +// glvPhi1 ^ 3 = 1 +var glvPhi1 = &fe{0xcd03c9e48671f071, 0x5dab22461fcda5d2, 0x587042afd3851b95, 0x8eb60ebe01bacb9e, 0x03f97d6e83d050d2, 0x18f0206554638741} + +// glvPhi2 ^ 3 = 1 +var glvPhi2 = &fe{0x30f1361b798a64e8, 0xf3b8ddab7ece5a2a, 0x16a8ca3ac61577f7, 0xc26a2ff874fd029b, 0x3636b76660701c6e, 0x051ba4ab241b6160} + +var glvMulWindowG1 uint = 4 +var glvMulWindowG2 uint = 4 + +type glvVector interface { + wnaf(w uint) (nafNumber, nafNumber) +} + +type glvVectorFr struct { + k1 *Fr + k2 *Fr + neg1 bool + neg2 bool +} + +type glvVectorBig struct { + k1 *big.Int + k2 *big.Int +} + +func (v *glvVectorFr) wnaf(w uint) (nafNumber, nafNumber) { + naf1 := v.k1.toWNAF(w) + naf2 := v.k2.toWNAF(w) + if v.neg1 { + naf1.neg() + } + if !v.neg2 { + naf2.neg() + } + return naf1, naf2 +} + +func (v *glvVectorBig) wnaf(w uint) (nafNumber, nafNumber) { + naf1, naf2 := bigToWNAF(v.k1, w), bigToWNAF(v.k2, w) + zero := new(big.Int) + if v.k1.Cmp(zero) < 0 { + naf1.neg() + } + if v.k2.Cmp(zero) > 0 { + naf2.neg() + } + return naf1, naf2 +} + +func (v *glvVectorFr) new(m *Fr) *glvVectorFr { + // Guide to Pairing Based Cryptography + // 6.3.2. Decompositions for the k = 12 BLS Family + + // alpha1 = round(x^2 * m / r) + alpha1 := alpha1(m) + // alpha2 = round(m / r) + alpha2 := alpha2(m) + + z1, z2 := new(Fr), new(Fr) + + // z1 = (x^2 - 1) * round(x^2 * m / r) + z1.Mul(alpha1, glvB1) + // z2 = x^2 * round(m / r) + z2.Mul(alpha2, glvB2) + + k1, k2 := new(Fr), new(Fr) + // k1 = m - z1 - alpha2 + k1.Sub(m, z1) + k1.Sub(k1, alpha2) + + // k2 = z2 - alpha1 + k2.Sub(z2, alpha1) + + if k1.Cmp(r128) == 1 { + k1.Neg(k1) + v.neg1 = true + } + v.k1 = new(Fr).Set(k1) + if k2.Cmp(r128) == 1 { + k2.Neg(k2) + v.neg2 = true + } + v.k2 = new(Fr).Set(k2) + return v +} + +func (v *glvVectorBig) new(m *big.Int) *glvVectorBig { + // Guide to Pairing Based Cryptography + // 6.3.2. Decompositions for the k = 12 BLS Family + + // alpha1 = round(x^2 * m / r) + alpha1 := new(big.Int).Mul(m, glvQ1Big) + alpha1.Add(alpha1, halfRBig) + alpha1.Rsh(alpha1, fourWordBitSize) + + // alpha2 = round(m / r) + alpha2 := new(big.Int).Mul(m, glvQ2Big) + alpha2.Add(alpha2, halfRBig) + alpha2.Rsh(alpha2, fourWordBitSize) + + z1, z2 := new(big.Int), new(big.Int) + // z1 = (x^2 - 1) * round(x^2 * m / r) + z1.Mul(alpha1, glvB1Big).Mod(z1, qBig) + // z2 = x^2 * round(m / r) + z2.Mul(alpha2, glvB2Big).Mod(z2, qBig) + + k1, k2 := new(big.Int), new(big.Int) + + // k1 = m - z1 - alpha2 + k1.Sub(m, z1) + k1.Sub(k1, alpha2) + + // k2 = z2 - alpha1 + k2.Sub(z2, alpha1) + + v.k1 = new(big.Int).Set(k1) + v.k2 = new(big.Int).Set(k2) + return v +} + +// round(x^2 * m / q) +func alpha1(m *Fr) *Fr { + a := new(wideFr) + a.mul(m, glvQ1) + return a.round() +} + +// round(m / q) +func alpha2(m *Fr) *Fr { + a := new(wideFr) + a.mul(m, glvQ2) + return a.round() +} + +func phi(a, b *fe) { + mul(a, b, glvPhi1) +} + +func (e *fp2) phi(a, b *fe2) { + mul(&a[0], &b[0], glvPhi2) + mul(&a[1], &b[1], glvPhi2) +} + +func (g *G1) glvEndomorphism(r, p *PointG1) { + t := g.Affine(p) + if g.IsZero(p) { + r.Zero() + return + } + r[1].set(&t[1]) + phi(&r[0], &t[0]) + r[2].one() +} + +func (g *G2) glvEndomorphism(r, p *PointG2) { + t := g.Affine(p) + if g.IsZero(p) { + r.Zero() + return + } + r[1].set(&t[1]) + g.f.phi(&r[0], &t[0]) + r[2].one() +} diff --git a/vendor/github.com/kilic/bls12-381/gt.go b/vendor/github.com/kilic/bls12-381/gt.go new file mode 100644 index 00000000000..846c9e9f595 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/gt.go @@ -0,0 +1,106 @@ +package bls12381 + +import ( + "errors" + "math/big" +) + +// E is type for target group element +type E = fe12 + +// GT is type for target multiplicative group GT. +type GT struct { + fp12 *fp12 +} + +// Set copies given value into the destination +func (e *E) Set(e2 *E) *E { + return e.set(e2) +} + +// One sets a new target group element to one +func (e *E) One() *E { + e = new(fe12).one() + return e +} + +// IsOne returns true if given element equals to one +func (e *E) IsOne() bool { + return e.isOne() +} + +// Equal returns true if given two element is equal, otherwise returns false +func (g *E) Equal(g2 *E) bool { + return g.equal(g2) +} + +// NewGT constructs new target group instance. +func NewGT() *GT { + fp12 := newFp12(nil) + return >{fp12} +} + +// Q returns group order in big.Int. +func (g *GT) Q() *big.Int { + return new(big.Int).Set(qBig) +} + +// FromBytes expects 576 byte input and returns target group element +// FromBytes returns error if given element is not on correct subgroup. +func (g *GT) FromBytes(in []byte) (*E, error) { + e, err := g.fp12.fromBytes(in) + if err != nil { + return nil, err + } + if !g.IsValid(e) { + return e, errors.New("invalid element") + } + return e, nil +} + +// ToBytes serializes target group element. +func (g *GT) ToBytes(e *E) []byte { + return g.fp12.toBytes(e) +} + +// IsValid checks whether given target group element is in correct subgroup. +func (g *GT) IsValid(e *E) bool { + r := g.New() + g.fp12.exp(r, e, qBig) + return r.isOne() +} + +// New initializes a new target group element which is equal to one +func (g *GT) New() *E { + return new(E).One() +} + +// Add adds two field element `a` and `b` and assigns the result to the element in first argument. +func (g *GT) Add(c, a, b *E) { + g.fp12.add(c, a, b) +} + +// Sub subtracts two field element `a` and `b`, and assigns the result to the element in first argument. +func (g *GT) Sub(c, a, b *E) { + g.fp12.sub(c, a, b) +} + +// Mul multiplies two field element `a` and `b` and assigns the result to the element in first argument. +func (g *GT) Mul(c, a, b *E) { + g.fp12.mul(c, a, b) +} + +// Square squares an element `a` and assigns the result to the element in first argument. +func (g *GT) Square(c, a *E) { + g.fp12.cyclotomicSquare(c, a) +} + +// Exp exponents an element `a` by a scalar `s` and assigns the result to the element in first argument. +func (g *GT) Exp(c, a *E, s *big.Int) { + g.fp12.cyclotomicExp(c, a, s) +} + +// Inverse inverses an element `a` and assigns the result to the element in first argument. +func (g *GT) Inverse(c, a *E) { + g.fp12.inverse(c, a) +} diff --git a/vendor/github.com/kilic/bls12-381/hash_to_field.go b/vendor/github.com/kilic/bls12-381/hash_to_field.go new file mode 100644 index 00000000000..9e440076916 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/hash_to_field.go @@ -0,0 +1,70 @@ +package bls12381 + +import ( + "crypto/sha256" + "errors" +) + +func hashToFpXMDSHA256(msg []byte, domain []byte, count int) ([]*fe, error) { + randBytes, err := expandMsgSHA256XMD(msg, domain, count*64) + if err != nil { + return nil, err + } + els := make([]*fe, count) + for i := 0; i < count; i++ { + els[i], err = from64Bytes(randBytes[i*64 : (i+1)*64]) + if err != nil { + return nil, err + } + } + return els, nil +} + +func expandMsgSHA256XMD(msg []byte, domain []byte, outLen int) ([]byte, error) { + h := sha256.New() + domainLen := uint8(len(domain)) + if domainLen > 255 { + return nil, errors.New("invalid domain length") + } + // DST_prime = DST || I2OSP(len(DST), 1) + // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) + _, _ = h.Write(make([]byte, h.BlockSize())) + _, _ = h.Write(msg) + _, _ = h.Write([]byte{uint8(outLen >> 8), uint8(outLen)}) + _, _ = h.Write([]byte{0}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + b0 := h.Sum(nil) + + // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) + h.Reset() + _, _ = h.Write(b0) + _, _ = h.Write([]byte{1}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + b1 := h.Sum(nil) + + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + ell := (outLen + h.Size() - 1) / h.Size() + bi := b1 + out := make([]byte, outLen) + for i := 1; i < ell; i++ { + h.Reset() + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + tmp := make([]byte, h.Size()) + for j := 0; j < h.Size(); j++ { + tmp[j] = b0[j] ^ bi[j] + } + _, _ = h.Write(tmp) + _, _ = h.Write([]byte{1 + uint8(i)}) + _, _ = h.Write(domain) + _, _ = h.Write([]byte{domainLen}) + + // b_1 || ... || b_(ell - 1) + copy(out[(i-1)*h.Size():i*h.Size()], bi[:]) + bi = h.Sum(nil) + } + // b_ell + copy(out[(ell-1)*h.Size():], bi[:]) + return out[:outLen], nil +} diff --git a/vendor/github.com/kilic/bls12-381/isogeny.go b/vendor/github.com/kilic/bls12-381/isogeny.go new file mode 100644 index 00000000000..76a803ad72b --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/isogeny.go @@ -0,0 +1,211 @@ +package bls12381 + +// isogenyMapG1 applies 11-isogeny map for BLS12-381 G1 defined at draft-irtf-cfrg-hash-to-curve-06. +func isogenyMapG1(x, y *fe) { + // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.2 + params := isogenyConstansG1 + degree := 15 + xNum, xDen, yNum, yDen := new(fe), new(fe), new(fe), new(fe) + xNum.set(params[0][degree]) + xDen.set(params[1][degree]) + yNum.set(params[2][degree]) + yDen.set(params[3][degree]) + for i := degree - 1; i >= 0; i-- { + mul(xNum, xNum, x) + mul(xDen, xDen, x) + mul(yNum, yNum, x) + mul(yDen, yDen, x) + add(xNum, xNum, params[0][i]) + add(xDen, xDen, params[1][i]) + add(yNum, yNum, params[2][i]) + add(yDen, yDen, params[3][i]) + } + inverse(xDen, xDen) + inverse(yDen, yDen) + mul(xNum, xNum, xDen) + mul(yNum, yNum, yDen) + mul(yNum, yNum, y) + x.set(xNum) + y.set(yNum) +} + +// isogenyMapG2 applies 11-isogeny map for BLS12-381 G1 defined at draft-irtf-cfrg-hash-to-curve-06. +func isogenyMapG2(e *fp2, x, y *fe2) { + if e == nil { + e = newFp2() + } + // https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#appendix-C.2 + params := isogenyConstantsG2 + degree := 3 + xNum := new(fe2).set(params[0][degree]) + xDen := new(fe2).set(params[1][degree]) + yNum := new(fe2).set(params[2][degree]) + yDen := new(fe2).set(params[3][degree]) + for i := degree - 1; i >= 0; i-- { + e.mul(xNum, xNum, x) + e.mul(xDen, xDen, x) + e.mul(yNum, yNum, x) + e.mul(yDen, yDen, x) + e.add(xNum, xNum, params[0][i]) + e.add(xDen, xDen, params[1][i]) + e.add(yNum, yNum, params[2][i]) + e.add(yDen, yDen, params[3][i]) + } + e.inverse(xDen, xDen) + e.inverse(yDen, yDen) + e.mul(xNum, xNum, xDen) + e.mul(yNum, yNum, yDen) + e.mul(yNum, yNum, y) + x.set(xNum) + y.set(yNum) +} + +var isogenyConstansG1 = [4][16]*fe{ + [16]*fe{ + &fe{0x4d18b6f3af00131c, 0x19fa219793fee28c, 0x3f2885f1467f19ae, 0x23dcea34f2ffb304, 0xd15b58d2ffc00054, 0x0913be200a20bef4}, + &fe{0x898985385cdbbd8b, 0x3c79e43cc7d966aa, 0x1597e193f4cd233a, 0x8637ef1e4d6623ad, 0x11b22deed20d827b, 0x07097bc5998784ad}, + &fe{0xa542583a480b664b, 0xfc7169c026e568c6, 0x5ba2ef314ed8b5a6, 0x5b5491c05102f0e7, 0xdf6e99707d2a0079, 0x0784151ed7605524}, + &fe{0x494e212870f72741, 0xab9be52fbda43021, 0x26f5577994e34c3d, 0x049dfee82aefbd60, 0x65dadd7828505289, 0x0e93d431ea011aeb}, + &fe{0x90ee774bd6a74d45, 0x7ada1c8a41bfb185, 0x0f1a8953b325f464, 0x104c24211be4805c, 0x169139d319ea7a8f, 0x09f20ead8e532bf6}, + &fe{0x6ddd93e2f43626b7, 0xa5482c9aa1ccd7bd, 0x143245631883f4bd, 0x2e0a94ccf77ec0db, 0xb0282d480e56489f, 0x18f4bfcbb4368929}, + &fe{0x23c5f0c953402dfd, 0x7a43ff6958ce4fe9, 0x2c390d3d2da5df63, 0xd0df5c98e1f9d70f, 0xffd89869a572b297, 0x1277ffc72f25e8fe}, + &fe{0x79f4f0490f06a8a6, 0x85f894a88030fd81, 0x12da3054b18b6410, 0xe2a57f6505880d65, 0xbba074f260e400f1, 0x08b76279f621d028}, + &fe{0xe67245ba78d5b00b, 0x8456ba9a1f186475, 0x7888bff6e6b33bb4, 0xe21585b9a30f86cb, 0x05a69cdcef55feee, 0x09e699dd9adfa5ac}, + &fe{0x0de5c357bff57107, 0x0a0db4ae6b1a10b2, 0xe256bb67b3b3cd8d, 0x8ad456574e9db24f, 0x0443915f50fd4179, 0x098c4bf7de8b6375}, + &fe{0xe6b0617e7dd929c7, 0xfe6e37d442537375, 0x1dafdeda137a489e, 0xe4efd1ad3f767ceb, 0x4a51d8667f0fe1cf, 0x054fdf4bbf1d821c}, + &fe{0x72db2a50658d767b, 0x8abf91faa257b3d5, 0xe969d6833764ab47, 0x464170142a1009eb, 0xb14f01aadb30be2f, 0x18ae6a856f40715d}, + &fe{0, 0, 0, 0, 0, 0}, + &fe{0, 0, 0, 0, 0, 0}, + &fe{0, 0, 0, 0, 0, 0}, + &fe{0, 0, 0, 0, 0, 0}, + }, + [16]*fe{ + &fe{0xb962a077fdb0f945, 0xa6a9740fefda13a0, 0xc14d568c3ed6c544, 0xb43fc37b908b133e, 0x9c0b3ac929599016, 0x0165aa6c93ad115f}, + &fe{0x23279a3ba506c1d9, 0x92cfca0a9465176a, 0x3b294ab13755f0ff, 0x116dda1c5070ae93, 0xed4530924cec2045, 0x083383d6ed81f1ce}, + &fe{0x9885c2a6449fecfc, 0x4a2b54ccd37733f0, 0x17da9ffd8738c142, 0xa0fba72732b3fafd, 0xff364f36e54b6812, 0x0f29c13c660523e2}, + &fe{0xe349cc118278f041, 0xd487228f2f3204fb, 0xc9d325849ade5150, 0x43a92bd69c15c2df, 0x1c2c7844bc417be4, 0x12025184f407440c}, + &fe{0x587f65ae6acb057b, 0x1444ef325140201f, 0xfbf995e71270da49, 0xccda066072436a42, 0x7408904f0f186bb2, 0x13b93c63edf6c015}, + &fe{0xfb918622cd141920, 0x4a4c64423ecaddb4, 0x0beb232927f7fb26, 0x30f94df6f83a3dc2, 0xaeedd424d780f388, 0x06cc402dd594bbeb}, + &fe{0xd41f761151b23f8f, 0x32a92465435719b3, 0x64f436e888c62cb9, 0xdf70a9a1f757c6e4, 0x6933a38d5b594c81, 0x0c6f7f7237b46606}, + &fe{0x693c08747876c8f7, 0x22c9850bf9cf80f0, 0x8e9071dab950c124, 0x89bc62d61c7baf23, 0xbc6be2d8dad57c23, 0x17916987aa14a122}, + &fe{0x1be3ff439c1316fd, 0x9965243a7571dfa7, 0xc7f7f62962f5cd81, 0x32c6aa9af394361c, 0xbbc2ee18e1c227f4, 0x0c102cbac531bb34}, + &fe{0x997614c97bacbf07, 0x61f86372b99192c0, 0x5b8c95fc14353fc3, 0xca2b066c2a87492f, 0x16178f5bbf698711, 0x12a6dcd7f0f4e0e8}, + &fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, + &fe{0, 0, 0, 0, 0, 0}, + &fe{0, 0, 0, 0, 0, 0}, + &fe{0, 0, 0, 0, 0, 0}, + &fe{0, 0, 0, 0, 0, 0}, + &fe{0, 0, 0, 0, 0, 0}, + }, + [16]*fe{ + &fe{0x2b567ff3e2837267, 0x1d4d9e57b958a767, 0xce028fea04bd7373, 0xcc31a30a0b6cd3df, 0x7d7b18a682692693, 0x0d300744d42a0310}, + &fe{0x99c2555fa542493f, 0xfe7f53cc4874f878, 0x5df0608b8f97608a, 0x14e03832052b49c8, 0x706326a6957dd5a4, 0x0a8dadd9c2414555}, + &fe{0x13d942922a5cf63a, 0x357e33e36e261e7d, 0xcf05a27c8456088d, 0x0000bd1de7ba50f0, 0x83d0c7532f8c1fde, 0x13f70bf38bbf2905}, + &fe{0x5c57fd95bfafbdbb, 0x28a359a65e541707, 0x3983ceb4f6360b6d, 0xafe19ff6f97e6d53, 0xb3468f4550192bf7, 0x0bb6cde49d8ba257}, + &fe{0x590b62c7ff8a513f, 0x314b4ce372cacefd, 0x6bef32ce94b8a800, 0x6ddf84a095713d5f, 0x64eace4cb0982191, 0x0386213c651b888d}, + &fe{0xa5310a31111bbcdd, 0xa14ac0f5da148982, 0xf9ad9cc95423d2e9, 0xaa6ec095283ee4a7, 0xcf5b1f022e1c9107, 0x01fddf5aed881793}, + &fe{0x65a572b0d7a7d950, 0xe25c2d8183473a19, 0xc2fcebe7cb877dbd, 0x05b2d36c769a89b0, 0xba12961be86e9efb, 0x07eb1b29c1dfde1f}, + &fe{0x93e09572f7c4cd24, 0x364e929076795091, 0x8569467e68af51b5, 0xa47da89439f5340f, 0xf4fa918082e44d64, 0x0ad52ba3e6695a79}, + &fe{0x911429844e0d5f54, 0xd03f51a3516bb233, 0x3d587e5640536e66, 0xfa86d2a3a9a73482, 0xa90ed5adf1ed5537, 0x149c9c326a5e7393}, + &fe{0x462bbeb03c12921a, 0xdc9af5fa0a274a17, 0x9a558ebde836ebed, 0x649ef8f11a4fae46, 0x8100e1652b3cdc62, 0x1862bd62c291dacb}, + &fe{0x05c9b8ca89f12c26, 0x0194160fa9b9ac4f, 0x6a643d5a6879fa2c, 0x14665bdd8846e19d, 0xbb1d0d53af3ff6bf, 0x12c7e1c3b28962e5}, + &fe{0xb55ebf900b8a3e17, 0xfedc77ec1a9201c4, 0x1f07db10ea1a4df4, 0x0dfbd15dc41a594d, 0x389547f2334a5391, 0x02419f98165871a4}, + &fe{0xb416af000745fc20, 0x8e563e9d1ea6d0f5, 0x7c763e17763a0652, 0x01458ef0159ebbef, 0x8346fe421f96bb13, 0x0d2d7b829ce324d2}, + &fe{0x93096bb538d64615, 0x6f2a2619951d823a, 0x8f66b3ea59514fa4, 0xf563e63704f7092f, 0x724b136c4cf2d9fa, 0x046959cfcfd0bf49}, + &fe{0xea748d4b6e405346, 0x91e9079c2c02d58f, 0x41064965946d9b59, 0xa06731f1d2bbe1ee, 0x07f897e267a33f1b, 0x1017290919210e5f}, + &fe{0x872aa6c17d985097, 0xeecc53161264562a, 0x07afe37afff55002, 0x54759078e5be6838, 0xc4b92d15db8acca8, 0x106d87d1b51d13b9}, + }, + [16]*fe{ + &fe{0xeb6c359d47e52b1c, 0x18ef5f8a10634d60, 0xddfa71a0889d5b7e, 0x723e71dcc5fc1323, 0x52f45700b70d5c69, 0x0a8b981ee47691f1}, + &fe{0x616a3c4f5535b9fb, 0x6f5f037395dbd911, 0xf25f4cc5e35c65da, 0x3e50dffea3c62658, 0x6a33dca523560776, 0x0fadeff77b6bfe3e}, + &fe{0x2be9b66df470059c, 0x24a2c159a3d36742, 0x115dbe7ad10c2a37, 0xb6634a652ee5884d, 0x04fe8bb2b8d81af4, 0x01c2a7a256fe9c41}, + &fe{0xf27bf8ef3b75a386, 0x898b367476c9073f, 0x24482e6b8c2f4e5f, 0xc8e0bbd6fe110806, 0x59b0c17f7631448a, 0x11037cd58b3dbfbd}, + &fe{0x31c7912ea267eec6, 0x1dbf6f1c5fcdb700, 0xd30d4fe3ba86fdb1, 0x3cae528fbee9a2a4, 0xb1cce69b6aa9ad9a, 0x044393bb632d94fb}, + &fe{0xc66ef6efeeb5c7e8, 0x9824c289dd72bb55, 0x71b1a4d2f119981d, 0x104fc1aafb0919cc, 0x0e49df01d942a628, 0x096c3a09773272d4}, + &fe{0x9abc11eb5fadeff4, 0x32dca50a885728f0, 0xfb1fa3721569734c, 0xc4b76271ea6506b3, 0xd466a75599ce728e, 0x0c81d4645f4cb6ed}, + &fe{0x4199f10e5b8be45b, 0xda64e495b1e87930, 0xcb353efe9b33e4ff, 0x9e9efb24aa6424c6, 0xf08d33680a237465, 0x0d3378023e4c7406}, + &fe{0x7eb4ae92ec74d3a5, 0xc341b4aa9fac3497, 0x5be603899e907687, 0x03bfd9cca75cbdeb, 0x564c2935a96bfa93, 0x0ef3c33371e2fdb5}, + &fe{0x7ee91fd449f6ac2e, 0xe5d5bd5cb9357a30, 0x773a8ca5196b1380, 0xd0fda172174ed023, 0x6cb95e0fa776aead, 0x0d22d5a40cec7cff}, + &fe{0xf727e09285fd8519, 0xdc9d55a83017897b, 0x7549d8bd057894ae, 0x178419613d90d8f8, 0xfce95ebdeb5b490a, 0x0467ffaef23fc49e}, + &fe{0xc1769e6a7c385f1b, 0x79bc930deac01c03, 0x5461c75a23ede3b5, 0x6e20829e5c230c45, 0x828e0f1e772a53cd, 0x116aefa749127bff}, + &fe{0x101c10bf2744c10a, 0xbbf18d053a6a3154, 0xa0ecf39ef026f602, 0xfc009d4996dc5153, 0xb9000209d5bd08d3, 0x189e5fe4470cd73c}, + &fe{0x7ebd546ca1575ed2, 0xe47d5a981d081b55, 0x57b2b625b6d4ca21, 0xb0a1ba04228520cc, 0x98738983c2107ff3, 0x13dddbc4799d81d6}, + &fe{0x09319f2e39834935, 0x039e952cbdb05c21, 0x55ba77a9a2f76493, 0xfd04e3dfc6086467, 0xfb95832e7d78742e, 0x0ef9c24eccaf5e0e}, + &fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, + }, +} + +var isogenyConstantsG2 = [4][4]*fe2{ + [4]*fe2{ + &fe2{ + fe{0x47f671c71ce05e62, 0x06dd57071206393e, 0x7c80cd2af3fd71a2, 0x048103ea9e6cd062, 0xc54516acc8d037f6, 0x13808f550920ea41}, + fe{0x47f671c71ce05e62, 0x06dd57071206393e, 0x7c80cd2af3fd71a2, 0x048103ea9e6cd062, 0xc54516acc8d037f6, 0x13808f550920ea41}, + }, + &fe2{ + fe{0, 0, 0, 0, 0, 0}, + fe{0x5fe55555554c71d0, 0x873fffdd236aaaa3, 0x6a6b4619b26ef918, 0x21c2888408874945, 0x2836cda7028cabc5, 0x0ac73310a7fd5abd}, + }, + &fe2{ + fe{0x0a0c5555555971c3, 0xdb0c00101f9eaaae, 0xb1fb2f941d797997, 0xd3960742ef416e1c, 0xb70040e2c20556f4, 0x149d7861e581393b}, + fe{0xaff2aaaaaaa638e8, 0x439fffee91b55551, 0xb535a30cd9377c8c, 0x90e144420443a4a2, 0x941b66d3814655e2, 0x0563998853fead5e}, + }, + &fe2{ + fe{0x40aac71c71c725ed, 0x190955557a84e38e, 0xd817050a8f41abc3, 0xd86485d4c87f6fb1, 0x696eb479f885d059, 0x198e1a74328002d2}, + fe{0, 0, 0, 0, 0, 0}, + }, + }, + [4]*fe2{ + &fe2{ + fe{0, 0, 0, 0, 0, 0}, + fe{0x1f3affffff13ab97, 0xf25bfc611da3ff3e, 0xca3757cb3819b208, 0x3e6427366f8cec18, 0x03977bc86095b089, 0x04f69db13f39a952}, + }, + &fe2{ + fe{0x447600000027552e, 0xdcb8009a43480020, 0x6f7ee9ce4a6e8b59, 0xb10330b7c0a95bc6, 0x6140b1fcfb1e54b7, 0x0381be097f0bb4e1}, + fe{0x7588ffffffd8557d, 0x41f3ff646e0bffdf, 0xf7b1e8d2ac426aca, 0xb3741acd32dbb6f8, 0xe9daf5b9482d581f, 0x167f53e0ba7431b8}, + }, + &fe2{ + fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, + fe{0, 0, 0, 0, 0, 0}, + }, + &fe2{ + fe{0, 0, 0, 0, 0, 0}, + fe{0, 0, 0, 0, 0, 0}, + }, + }, + [4]*fe2{ + &fe2{ + fe{0x96d8f684bdfc77be, 0xb530e4f43b66d0e2, 0x184a88ff379652fd, 0x57cb23ecfae804e1, 0x0fd2e39eada3eba9, 0x08c8055e31c5d5c3}, + fe{0x96d8f684bdfc77be, 0xb530e4f43b66d0e2, 0x184a88ff379652fd, 0x57cb23ecfae804e1, 0x0fd2e39eada3eba9, 0x08c8055e31c5d5c3}, + }, + &fe2{ + fe{0, 0, 0, 0, 0, 0}, + fe{0xbf0a71c71c91b406, 0x4d6d55d28b7638fd, 0x9d82f98e5f205aee, 0xa27aa27b1d1a18d5, 0x02c3b2b2d2938e86, 0x0c7d13420b09807f}, + }, + &fe2{ + fe{0xd7f9555555531c74, 0x21cffff748daaaa8, 0x5a9ad1866c9bbe46, 0x4870a2210221d251, 0x4a0db369c0a32af1, 0x02b1ccc429ff56af}, + fe{0xe205aaaaaaac8e37, 0xfcdc000768795556, 0x0c96011a8a1537dd, 0x1c06a963f163406e, 0x010df44c82a881e6, 0x174f45260f808feb}, + }, + &fe2{ + fe{0xa470bda12f67f35c, 0xc0fe38e23327b425, 0xc9d3d0f2c6f0678d, 0x1c55c9935b5a982e, 0x27f6c0e2f0746764, 0x117c5e6e28aa9054}, + fe{0, 0, 0, 0, 0, 0}, + }, + }, + [4]*fe2{ + &fe2{ + fe{0x0162fffffa765adf, 0x8f7bea480083fb75, 0x561b3c2259e93611, 0x11e19fc1a9c875d5, 0xca713efc00367660, 0x03c6a03d41da1151}, + fe{0x0162fffffa765adf, 0x8f7bea480083fb75, 0x561b3c2259e93611, 0x11e19fc1a9c875d5, 0xca713efc00367660, 0x03c6a03d41da1151}, + }, + &fe2{ + fe{0, 0, 0, 0, 0, 0}, + fe{0x5db0fffffd3b02c5, 0xd713f52358ebfdba, 0x5ea60761a84d161a, 0xbb2c75a34ea6c44a, 0x0ac6735921c1119b, 0x0ee3d913bdacfbf6}, + }, + &fe2{ + fe{0x66b10000003affc5, 0xcb1400e764ec0030, 0xa73e5eb56fa5d106, 0x8984c913a0fe09a9, 0x11e10afb78ad7f13, 0x05429d0e3e918f52}, + fe{0x534dffffffc4aae6, 0x5397ff174c67ffcf, 0xbff273eb870b251d, 0xdaf2827152870915, 0x393a9cbaca9e2dc3, 0x14be74dbfaee5748}, + }, + &fe2{ + fe{0x760900000002fffd, 0xebf4000bc40c0002, 0x5f48985753c758ba, 0x77ce585370525745, 0x5c071a97a256ec6d, 0x15f65ec3fa80e493}, + fe{0, 0, 0, 0, 0, 0}, + }, + }, +} diff --git a/vendor/github.com/kilic/bls12-381/pairing.go b/vendor/github.com/kilic/bls12-381/pairing.go new file mode 100644 index 00000000000..61eab51b680 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/pairing.go @@ -0,0 +1,348 @@ +package bls12381 + +type pair struct { + g1 *PointG1 + g2 *PointG2 +} + +func newPair(g1 *PointG1, g2 *PointG2) pair { + return pair{g1, g2} +} + +// Engine is BLS12-381 elliptic curve pairing engine +type Engine struct { + G1 *G1 + G2 *G2 + fp12 *fp12 + fp2 *fp2 + pairingEngineTemp + pairs []pair +} + +// NewEngine creates new pairing engine insteace. +func NewEngine() *Engine { + fp2 := newFp2() + fp6 := newFp6(fp2) + fp12 := newFp12(fp6) + g1 := NewG1() + g2 := newG2(fp2) + return &Engine{ + fp2: fp2, + fp12: fp12, + G1: g1, + G2: g2, + pairingEngineTemp: newEngineTemp(), + } +} + +type pairingEngineTemp struct { + t2 [10]*fe2 + t12 [9]fe12 +} + +func newEngineTemp() pairingEngineTemp { + t2 := [10]*fe2{} + for i := 0; i < 10; i++ { + t2[i] = &fe2{} + } + t12 := [9]fe12{} + return pairingEngineTemp{t2, t12} +} + +// AddPair adds a g1, g2 point pair to pairing engine +func (e *Engine) AddPair(g1 *PointG1, g2 *PointG2) *Engine { + p := newPair(g1, g2) + if !(e.G1.IsZero(p.g1) || e.G2.IsZero(p.g2)) { + e.G1.Affine(p.g1) + e.G2.Affine(p.g2) + e.pairs = append(e.pairs, p) + } + return e +} + +// AddPairInv adds a G1, G2 point pair to pairing engine. G1 point is negated. +func (e *Engine) AddPairInv(g1 *PointG1, g2 *PointG2) *Engine { + ng1 := e.G1.New().Set(g1) + e.G1.Neg(ng1, g1) + e.AddPair(ng1, g2) + return e +} + +// Reset deletes added pairs. +func (e *Engine) Reset() *Engine { + e.pairs = []pair{} + return e +} + +func (e *Engine) doublingStep(coeff *fe6, r *PointG2) { + fp2 := e.fp2 + t := e.t2 + fp2.mul(t[0], &r[0], &r[1]) + fp2.mul0(t[0], t[0], twoInv) + fp2.square(t[1], &r[1]) + fp2.square(t[2], &r[2]) + fp2.double(t[7], t[2]) + fp2.addAssign(t[7], t[2]) + fp2.mulByB(t[3], t[7]) + fp2.double(t[4], t[3]) + fp2.addAssign(t[4], t[3]) + fp2.add(t[5], t[1], t[4]) + fp2.mul0(t[5], t[5], twoInv) + fp2.add(t[6], &r[1], &r[2]) + fp2.squareAssign(t[6]) + fp2.add(t[7], t[2], t[1]) + fp2.subAssign(t[6], t[7]) + fp2.sub(&coeff[0], t[3], t[1]) + fp2.square(t[7], &r[0]) + fp2.sub(t[4], t[1], t[4]) + fp2.mul(&r[0], t[4], t[0]) + fp2.square(t[2], t[3]) + fp2.double(t[3], t[2]) + fp2.addAssign(t[3], t[2]) + fp2.squareAssign(t[5]) + fp2.sub(&r[1], t[5], t[3]) + fp2.mul(&r[2], t[1], t[6]) + fp2.double(t[0], t[7]) + fp2.add(&coeff[1], t[0], t[7]) + fp2.neg(&coeff[2], t[6]) +} + +func (e *Engine) additionStep(coeff *fe6, r, q *PointG2) { + fp2 := e.fp2 + t := e.t2 + fp2.mul(t[0], &q[1], &r[2]) + fp2.neg(t[0], t[0]) + fp2.addAssign(t[0], &r[1]) + fp2.mul(t[1], &q[0], &r[2]) + fp2.neg(t[1], t[1]) + fp2.addAssign(t[1], &r[0]) + fp2.square(t[2], t[0]) + fp2.square(t[3], t[1]) + fp2.mul(t[4], t[1], t[3]) + fp2.mul(t[2], &r[2], t[2]) + fp2.mulAssign(t[3], &r[0]) + fp2.double(t[5], t[3]) + fp2.sub(t[5], t[4], t[5]) + fp2.addAssign(t[5], t[2]) + fp2.mul(&r[0], t[1], t[5]) + fp2.subAssign(t[3], t[5]) + fp2.mulAssign(t[3], t[0]) + fp2.mul(t[2], &r[1], t[4]) + fp2.sub(&r[1], t[3], t[2]) + fp2.mulAssign(&r[2], t[4]) + fp2.mul(t[2], t[1], &q[1]) + fp2.mul(t[3], t[0], &q[0]) + fp2.sub(&coeff[0], t[3], t[2]) + fp2.neg(&coeff[1], t[0]) + coeff[2].set(t[1]) +} + +func (e *Engine) precompute() [][68]fe6 { + n := len(e.pairs) + coeffs := make([][68]fe6, len(e.pairs)) + for i := 0; i < n; i++ { + r := new(PointG2).Set(e.pairs[i].g2) + j := 0 + for k := 62; k >= 0; k-- { + e.doublingStep(&coeffs[i][j], r) + if x&(1<= 0; i-- { + if i != 62 { + e.fp12.square(f, f) + } + e.lineEval(f, coeffs, j) + if x&(1< 1 && hex[:2] == "0x" { + hex = hex[2:] + } + n, _ := new(big.Int).SetString(hex, 16) + return n +} diff --git a/vendor/github.com/kilic/bls12-381/wnaf.go b/vendor/github.com/kilic/bls12-381/wnaf.go new file mode 100644 index 00000000000..9ab2d573066 --- /dev/null +++ b/vendor/github.com/kilic/bls12-381/wnaf.go @@ -0,0 +1,110 @@ +package bls12381 + +import ( + "math/big" +) + +type nafNumber []int + +func (n nafNumber) neg() { + for i := 0; i < len(n); i++ { + n[i] = -n[i] + } +} + +var bigZero = big.NewInt(0) +var bigOne = big.NewInt(1) + +func (e *Fr) toWNAF(w uint) nafNumber { + naf := nafNumber{} + if w == 0 { + return naf + } + windowSize, halfSize, mask := 1<<(w+1), 1<= halfSize { + nafSign = nafSign - windowSize + } + naf = append(naf, int(nafSign)) + if nafSign < 0 { + laddAssignFR(ee, z.setUint64(uint64(-nafSign))) + } else { + lsubAssignFR(ee, z.setUint64(uint64(nafSign))) + } + } else { + naf = append(naf, 0) + } + ee.div2() + } + + return naf +} + +func (e *Fr) fromWNAF(naf nafNumber, w uint) *Fr { + if w == 0 { + return e + } + l := (1 << (w - 1)) + table := make([]*Fr, l) + table[0] = new(Fr).One() + two := new(Fr).setUint64(2) + for i := 1; i < l; i++ { + table[i] = new(Fr) + table[i].Add(table[i-1], two) + } + acc := new(Fr).Zero() + for i := len(naf) - 1; i >= 0; i-- { + if naf[i] < 0 { + acc.Sub(acc, table[-naf[i]>>1]) + } else if naf[i] > 0 { + acc.Add(acc, table[naf[i]>>1]) + } + if i != 0 { + acc.Double(acc) + } + } + return e.Set(acc) +} + +// caution: does not cover negative case +func bigToWNAF(e *big.Int, w uint) nafNumber { + naf := nafNumber{} + if w == 0 { + return naf + } + windowSize := new(big.Int).Lsh(bigOne, uint(w+1)) + halfSize := new(big.Int).Rsh(windowSize, 1) + ee := new(big.Int).Abs(e) + for ee.Cmp(bigZero) != 0 { + if ee.Bit(0) == 1 { + nafSign := new(big.Int) + nafSign.Mod(ee, windowSize) + if nafSign.Cmp(halfSize) >= 0 { + nafSign.Sub(nafSign, windowSize) + } + naf = append(naf, int(nafSign.Int64())) + ee.Sub(ee, nafSign) + } else { + naf = append(naf, 0) + } + ee.Rsh(ee, 1) + } + return naf +} + +func bigFromWNAF(naf nafNumber) *big.Int { + acc := new(big.Int) + k := new(big.Int).Set(bigOne) + for i := 0; i < len(naf); i++ { + if naf[i] != 0 { + z := new(big.Int).Mul(k, big.NewInt(int64(naf[i]))) + acc.Add(acc, z) + } + k.Lsh(k, 1) + } + return acc +} diff --git a/vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem.go b/vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem.go index 4e4c29459ed..98e4e38f4aa 100644 --- a/vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem.go +++ b/vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem.go @@ -1,6 +1,3 @@ -//go:build go1.12 -// +build go1.12 - package fmtsort import "reflect" diff --git a/vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem_1.11.go b/vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem_1.11.go deleted file mode 100644 index 873bf7f5e8e..00000000000 --- a/vendor/github.com/rogpeppe/go-internal/fmtsort/mapelem_1.11.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build !go1.12 -// +build !go1.12 - -package fmtsort - -import "reflect" - -const brokenNaNs = true - -func mapElems(mapValue reflect.Value) ([]reflect.Value, []reflect.Value) { - key := mapValue.MapKeys() - value := make([]reflect.Value, 0, len(key)) - for _, k := range key { - v := mapValue.MapIndex(k) - if !v.IsValid() { - // Note: we can't retrieve the value, probably because - // the key is NaN, so just do the best we can and - // add a zero value of the correct type in that case. - v = reflect.Zero(mapValue.Type().Elem()) - } - value = append(value, v) - } - return key, value -} diff --git a/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go b/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go index 0fb5187dd84..7f51854178f 100644 --- a/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go +++ b/vendor/github.com/rogpeppe/go-internal/fmtsort/sort.go @@ -36,19 +36,18 @@ func (o *SortedMap) Swap(i, j int) { // // The ordering rules are more general than with Go's < operator: // -// - when applicable, nil compares low -// - ints, floats, and strings order by < -// - NaN compares less than non-NaN floats -// - bool compares false before true -// - complex compares real, then imag -// - pointers compare by machine address -// - channel values compare by machine address -// - structs compare each field in turn -// - arrays compare each element in turn. -// Otherwise identical arrays compare by length. -// - interface values compare first by reflect.Type describing the concrete type -// and then by concrete value as described in the previous rules. -// +// - when applicable, nil compares low +// - ints, floats, and strings order by < +// - NaN compares less than non-NaN floats +// - bool compares false before true +// - complex compares real, then imag +// - pointers compare by machine address +// - channel values compare by machine address +// - structs compare each field in turn +// - arrays compare each element in turn. +// Otherwise identical arrays compare by length. +// - interface values compare first by reflect.Type describing the concrete type +// and then by concrete value as described in the previous rules. func Sort(mapValue reflect.Value) *SortedMap { if mapValue.Type().Kind() != reflect.Map { return nil diff --git a/vendor/github.com/spf13/cobra/.travis.yml b/vendor/github.com/spf13/cobra/.travis.yml deleted file mode 100644 index e0a3b50043b..00000000000 --- a/vendor/github.com/spf13/cobra/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: go - -stages: - - test - - build - -go: - - 1.12.x - - 1.13.x - - tip - -env: GO111MODULE=on - -before_install: - - go get -u github.com/kyoh86/richgo - - go get -u github.com/mitchellh/gox - - curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin latest - -matrix: - allow_failures: - - go: tip - include: - - stage: build - go: 1.13.x - script: make cobra_generator - -script: - - make test diff --git a/vendor/github.com/spf13/cobra/CHANGELOG.md b/vendor/github.com/spf13/cobra/CHANGELOG.md deleted file mode 100644 index 8a23b4f8513..00000000000 --- a/vendor/github.com/spf13/cobra/CHANGELOG.md +++ /dev/null @@ -1,51 +0,0 @@ -# Cobra Changelog - -## v1.1.3 - -* **Fix:** release-branch.cobra1.1 only: Revert "Deprecate Go < 1.14" to maintain backward compatibility - -## v1.1.2 - -### Notable Changes - -* Bump license year to 2021 in golden files (#1309) @Bowbaq -* Enhance PowerShell completion with custom comp (#1208) @Luap99 -* Update gopkg.in/yaml.v2 to v2.4.0: The previous breaking change in yaml.v2 v2.3.0 has been reverted, see go-yaml/yaml#670 -* Documentation readability improvements (#1228 etc.) @zaataylor etc. -* Use golangci-lint: Repair warnings and errors resulting from linting (#1044) @umarcor - -## v1.1.1 - -* **Fix:** yaml.v2 2.3.0 contained a unintended breaking change. This release reverts to yaml.v2 v2.2.8 which has recent critical CVE fixes, but does not have the breaking changes. See https://github.com/spf13/cobra/pull/1259 for context. -* **Fix:** correct internal formatting for go-md2man v2 (which caused man page generation to be broken). See https://github.com/spf13/cobra/issues/1049 for context. - -## v1.1.0 - -### Notable Changes - -* Extend Go completions and revamp zsh comp (#1070) -* Fix man page doc generation - no auto generated tag when `cmd.DisableAutoGenTag = true` (#1104) @jpmcb -* Add completion for help command (#1136) -* Complete subcommands when TraverseChildren is set (#1171) -* Fix stderr printing functions (#894) -* fix: fish output redirection (#1247) - -## v1.0.0 - -Announcing v1.0.0 of Cobra. 🎉 - -### Notable Changes -* Fish completion (including support for Go custom completion) @marckhouzam -* API (urgent): Rename BashCompDirectives to ShellCompDirectives @marckhouzam -* Remove/replace SetOutput on Command - deprecated @jpmcb -* add support for autolabel stale PR @xchapter7x -* Add Labeler Actions @xchapter7x -* Custom completions coded in Go (instead of Bash) @marckhouzam -* Partial Revert of #922 @jharshman -* Add Makefile to project @jharshman -* Correct documentation for InOrStdin @desponda -* Apply formatting to templates @jharshman -* Revert change so help is printed on stdout again @marckhouzam -* Update md2man to v2.0.0 @pdf -* update viper to v1.4.0 @umarcor -* Update cmd/root.go example in README.md @jharshman diff --git a/vendor/github.com/spf13/cobra/MAINTAINERS b/vendor/github.com/spf13/cobra/MAINTAINERS new file mode 100644 index 00000000000..4c5ac3dd997 --- /dev/null +++ b/vendor/github.com/spf13/cobra/MAINTAINERS @@ -0,0 +1,13 @@ +maintainers: +- spf13 +- johnSchnake +- jpmcb +- marckhouzam +inactive: +- anthonyfok +- bep +- bogem +- broady +- eparis +- jharshman +- wfernandes diff --git a/vendor/github.com/spf13/cobra/Makefile b/vendor/github.com/spf13/cobra/Makefile index 472c73bf16f..443ef1a987a 100644 --- a/vendor/github.com/spf13/cobra/Makefile +++ b/vendor/github.com/spf13/cobra/Makefile @@ -9,11 +9,11 @@ ifeq (, $(shell which richgo)) $(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo") endif -.PHONY: fmt lint test cobra_generator install_deps clean +.PHONY: fmt lint test install_deps clean default: all -all: fmt test cobra_generator +all: fmt test fmt: $(info ******************** checking formatting ********************) @@ -23,15 +23,10 @@ lint: $(info ******************** running lint tools ********************) golangci-lint run -v -test: install_deps lint +test: install_deps $(info ******************** running tests ********************) richgo test -v ./... -cobra_generator: install_deps - $(info ******************** building generator ********************) - mkdir -p $(BIN) - make -C cobra all - install_deps: $(info ******************** downloading dependencies ********************) go get -v ./... diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index a1b13ddda6c..2bf15208229 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -1,53 +1,26 @@ ![cobra logo](https://cloud.githubusercontent.com/assets/173412/10886352/ad566232-814f-11e5-9cd0-aa101788c117.png) -Cobra is both a library for creating powerful modern CLI applications as well as a program to generate applications and command files. +Cobra is a library for creating powerful modern CLI applications. -Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/), +Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/), [Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra. [![](https://img.shields.io/github/workflow/status/spf13/cobra/Test?longCache=tru&label=Test&logo=github%20actions&logoColor=fff)](https://github.com/spf13/cobra/actions?query=workflow%3ATest) -[![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra) -[![GoDoc](https://godoc.org/github.com/spf13/cobra?status.svg)](https://godoc.org/github.com/spf13/cobra) +[![Go Reference](https://pkg.go.dev/badge/github.com/spf13/cobra.svg)](https://pkg.go.dev/github.com/spf13/cobra) [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra) [![Slack](https://img.shields.io/badge/Slack-cobra-brightgreen)](https://gophers.slack.com/archives/CD3LP1199) -# Table of Contents - -- [Overview](#overview) -- [Concepts](#concepts) - * [Commands](#commands) - * [Flags](#flags) -- [Installing](#installing) -- [Getting Started](#getting-started) - * [Using the Cobra Generator](#using-the-cobra-generator) - * [Using the Cobra Library](#using-the-cobra-library) - * [Working with Flags](#working-with-flags) - * [Positional and Custom Arguments](#positional-and-custom-arguments) - * [Example](#example) - * [Help Command](#help-command) - * [Usage Message](#usage-message) - * [PreRun and PostRun Hooks](#prerun-and-postrun-hooks) - * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens) - * [Generating documentation for your command](#generating-documentation-for-your-command) - * [Generating shell completions](#generating-shell-completions) -- [Contributing](CONTRIBUTING.md) -- [License](#license) - # Overview Cobra is a library providing a simple interface to create powerful modern CLI interfaces similar to git & go tools. -Cobra is also an application that will generate your application scaffolding to rapidly -develop a Cobra-based application. - Cobra provides: * Easy subcommand-based CLIs: `app server`, `app fetch`, etc. * Fully POSIX-compliant flags (including short & long versions) * Nested subcommands * Global, local and cascading flags -* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname` * Intelligent suggestions (`app srver`... did you mean `app server`?) * Automatic help generation for commands and flags * Automatic help flag recognition of `-h`, `--help`, etc. @@ -55,7 +28,7 @@ Cobra provides: * Automatically generated man pages for your application * Command aliases so you can change things without breaking them * The flexibility to define your own help, usage, etc. -* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps +* Optional seamless integration with [viper](https://github.com/spf13/viper) for 12-factor apps # Concepts @@ -89,7 +62,7 @@ have children commands and optionally run an action. In the example above, 'server' is the command. -[More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command) +[More about cobra.Command](https://pkg.go.dev/github.com/spf13/cobra#Command) ## Flags @@ -106,654 +79,32 @@ which maintains the same interface while adding POSIX compliance. # Installing Using Cobra is easy. First, use `go get` to install the latest version -of the library. This command will install the `cobra` generator executable -along with the library and its dependencies: - - go get -u github.com/spf13/cobra - -Next, include Cobra in your application: - -```go -import "github.com/spf13/cobra" -``` - -# Getting Started - -While you are welcome to provide your own organization, typically a Cobra-based -application will follow the following organizational structure: - -``` - ▾ appName/ - ▾ cmd/ - add.go - your.go - commands.go - here.go - main.go -``` - -In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. - -```go -package main - -import ( - "{pathToYourApp}/cmd" -) - -func main() { - cmd.Execute() -} -``` - -## Using the Cobra Generator - -Cobra provides its own program that will create your application and add any -commands you want. It's the easiest way to incorporate Cobra into your application. - -[Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it. - -## Using the Cobra Library - -To manually implement Cobra you need to create a bare main.go file and a rootCmd file. -You will optionally provide additional commands as you see fit. - -### Create rootCmd - -Cobra doesn't require any special constructors. Simply create your commands. - -Ideally you place this in app/cmd/root.go: - -```go -var rootCmd = &cobra.Command{ - Use: "hugo", - Short: "Hugo is a very fast static site generator", - Long: `A Fast and Flexible Static Site Generator built with - love by spf13 and friends in Go. - Complete documentation is available at http://hugo.spf13.com`, - Run: func(cmd *cobra.Command, args []string) { - // Do Stuff Here - }, -} - -func Execute() { - if err := rootCmd.Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } -} -``` - -You will additionally define flags and handle configuration in your init() function. - -For example cmd/root.go: - -```go -package cmd - -import ( - "fmt" - "os" - - homedir "github.com/mitchellh/go-homedir" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var ( - // Used for flags. - cfgFile string - userLicense string - - rootCmd = &cobra.Command{ - Use: "cobra", - Short: "A generator for Cobra based Applications", - Long: `Cobra is a CLI library for Go that empowers applications. -This application is a tool to generate the needed files -to quickly create a Cobra application.`, - } -) - -// Execute executes the root command. -func Execute() error { - return rootCmd.Execute() -} - -func init() { - cobra.OnInitialize(initConfig) - - rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") - rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") - rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") - rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") - viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) - viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) - viper.SetDefault("author", "NAME HERE ") - viper.SetDefault("license", "apache") - - rootCmd.AddCommand(addCmd) - rootCmd.AddCommand(initCmd) -} - -func initConfig() { - if cfgFile != "" { - // Use config file from the flag. - viper.SetConfigFile(cfgFile) - } else { - // Find home directory. - home, err := homedir.Dir() - cobra.CheckErr(err) - - // Search config in home directory with name ".cobra" (without extension). - viper.AddConfigPath(home) - viper.SetConfigName(".cobra") - } - - viper.AutomaticEnv() - - if err := viper.ReadInConfig(); err == nil { - fmt.Println("Using config file:", viper.ConfigFileUsed()) - } -} -``` - -### Create your main.go - -With the root command you need to have your main function execute it. -Execute should be run on the root for clarity, though it can be called on any command. - -In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra. - -```go -package main - -import ( - "{pathToYourApp}/cmd" -) - -func main() { - cmd.Execute() -} -``` - -### Create additional commands - -Additional commands can be defined and typically are each given their own file -inside of the cmd/ directory. - -If you wanted to create a version command you would create cmd/version.go and -populate it with the following: - -```go -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func init() { - rootCmd.AddCommand(versionCmd) -} - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the version number of Hugo", - Long: `All software has versions. This is Hugo's`, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") - }, -} -``` - -### Returning and handling errors - -If you wish to return an error to the caller of a command, `RunE` can be used. - -```go -package cmd - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func init() { - rootCmd.AddCommand(tryCmd) -} - -var tryCmd = &cobra.Command{ - Use: "try", - Short: "Try and possibly fail at something", - RunE: func(cmd *cobra.Command, args []string) error { - if err := someFunc(); err != nil { - return err - } - return nil - }, -} -``` - -The error can then be caught at the execute function call. - -## Working with Flags - -Flags provide modifiers to control how the action command operates. - -### Assign flags to a command - -Since the flags are defined and used in different locations, we need to -define a variable outside with the correct scope to assign the flag to -work with. - -```go -var Verbose bool -var Source string -``` - -There are two different approaches to assign a flag. - -### Persistent Flags - -A flag can be 'persistent', meaning that this flag will be available to the -command it's assigned to as well as every command under that command. For -global flags, assign a flag as a persistent flag on the root. - -```go -rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") -``` - -### Local Flags - -A flag can also be assigned locally, which will only apply to that specific command. - -```go -localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") -``` - -### Local Flag on Parent Commands - -By default, Cobra only parses local flags on the target command, and any local flags on -parent commands are ignored. By enabling `Command.TraverseChildren`, Cobra will -parse local flags on each command before executing the target command. - -```go -command := cobra.Command{ - Use: "print [OPTIONS] [COMMANDS]", - TraverseChildren: true, -} -``` - -### Bind Flags with Config - -You can also bind your flags with [viper](https://github.com/spf13/viper): -```go -var author string +of the library. -func init() { - rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") - viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) -} ``` - -In this example, the persistent flag `author` is bound with `viper`. -**Note**: the variable `author` will not be set to the value from config, -when the `--author` flag is not provided by user. - -More in [viper documentation](https://github.com/spf13/viper#working-with-flags). - -### Required flags - -Flags are optional by default. If instead you wish your command to report an error -when a flag has not been set, mark it as required: -```go -rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)") -rootCmd.MarkFlagRequired("region") -``` - -Or, for persistent flags: -```go -rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)") -rootCmd.MarkPersistentFlagRequired("region") -``` - -## Positional and Custom Arguments - -Validation of positional arguments can be specified using the `Args` field -of `Command`. - -The following validators are built in: - -- `NoArgs` - the command will report an error if there are any positional args. -- `ArbitraryArgs` - the command will accept any args. -- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`. -- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. -- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. -- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. -- `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command` -- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. - -An example of setting the custom validator: - -```go -var cmd = &cobra.Command{ - Short: "hello", - Args: func(cmd *cobra.Command, args []string) error { - if len(args) < 1 { - return errors.New("requires a color argument") - } - if myapp.IsValidColor(args[0]) { - return nil - } - return fmt.Errorf("invalid color specified: %s", args[0]) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Hello, World!") - }, -} -``` - -## Example - -In the example below, we have defined three commands. Two are at the top level -and one (cmdTimes) is a child of one of the top commands. In this case the root -is not executable, meaning that a subcommand is required. This is accomplished -by not providing a 'Run' for the 'rootCmd'. - -We have only defined one flag for a single command. - -More documentation about flags is available at https://github.com/spf13/pflag - -```go -package main - -import ( - "fmt" - "strings" - - "github.com/spf13/cobra" -) - -func main() { - var echoTimes int - - var cmdPrint = &cobra.Command{ - Use: "print [string to print]", - Short: "Print anything to the screen", - Long: `print is for printing anything back to the screen. -For many years people have printed back to the screen.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Print: " + strings.Join(args, " ")) - }, - } - - var cmdEcho = &cobra.Command{ - Use: "echo [string to echo]", - Short: "Echo anything to the screen", - Long: `echo is for echoing anything back. -Echo works a lot like print, except it has a child command.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - fmt.Println("Echo: " + strings.Join(args, " ")) - }, - } - - var cmdTimes = &cobra.Command{ - Use: "times [string to echo]", - Short: "Echo anything to the screen more times", - Long: `echo things multiple times back to the user by providing -a count and a string.`, - Args: cobra.MinimumNArgs(1), - Run: func(cmd *cobra.Command, args []string) { - for i := 0; i < echoTimes; i++ { - fmt.Println("Echo: " + strings.Join(args, " ")) - } - }, - } - - cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") - - var rootCmd = &cobra.Command{Use: "app"} - rootCmd.AddCommand(cmdPrint, cmdEcho) - cmdEcho.AddCommand(cmdTimes) - rootCmd.Execute() -} -``` - -For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/). - -## Help Command - -Cobra automatically adds a help command to your application when you have subcommands. -This will be called when a user runs 'app help'. Additionally, help will also -support all other commands as input. Say, for instance, you have a command called -'create' without any additional configuration; Cobra will work when 'app help -create' is called. Every command will automatically have the '--help' flag added. - -### Example - -The following output is automatically generated by Cobra. Nothing beyond the -command and flag definitions are needed. - - $ cobra help - - Cobra is a CLI library for Go that empowers applications. - This application is a tool to generate the needed files - to quickly create a Cobra application. - - Usage: - cobra [command] - - Available Commands: - add Add a command to a Cobra Application - help Help about any command - init Initialize a Cobra Application - - Flags: - -a, --author string author name for copyright attribution (default "YOUR NAME") - --config string config file (default is $HOME/.cobra.yaml) - -h, --help help for cobra - -l, --license string name of license for the project - --viper use Viper for configuration (default true) - - Use "cobra [command] --help" for more information about a command. - - -Help is just a command like any other. There is no special logic or behavior -around it. In fact, you can provide your own if you want. - -### Defining your own help - -You can provide your own Help command or your own template for the default command to use -with following functions: - -```go -cmd.SetHelpCommand(cmd *Command) -cmd.SetHelpFunc(f func(*Command, []string)) -cmd.SetHelpTemplate(s string) +go get -u github.com/spf13/cobra@latest ``` -The latter two will also apply to any children commands. - -## Usage Message - -When the user provides an invalid flag or invalid command, Cobra responds by -showing the user the 'usage'. - -### Example -You may recognize this from the help above. That's because the default help -embeds the usage as part of its output. - - $ cobra --invalid - Error: unknown flag: --invalid - Usage: - cobra [command] - - Available Commands: - add Add a command to a Cobra Application - help Help about any command - init Initialize a Cobra Application - - Flags: - -a, --author string author name for copyright attribution (default "YOUR NAME") - --config string config file (default is $HOME/.cobra.yaml) - -h, --help help for cobra - -l, --license string name of license for the project - --viper use Viper for configuration (default true) - - Use "cobra [command] --help" for more information about a command. - -### Defining your own usage -You can provide your own usage function or template for Cobra to use. -Like help, the function and template are overridable through public methods: - -```go -cmd.SetUsageFunc(f func(*Command) error) -cmd.SetUsageTemplate(s string) -``` - -## Version Flag - -Cobra adds a top-level '--version' flag if the Version field is set on the root command. -Running an application with the '--version' flag will print the version to stdout using -the version template. The template can be customized using the -`cmd.SetVersionTemplate(s string)` function. - -## PreRun and PostRun Hooks - -It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: - -- `PersistentPreRun` -- `PreRun` -- `Run` -- `PostRun` -- `PersistentPostRun` - -An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: - -```go -package main - -import ( - "fmt" - - "github.com/spf13/cobra" -) - -func main() { - - var rootCmd = &cobra.Command{ - Use: "root [sub]", - Short: "My root command", - PersistentPreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) - }, - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) - }, - } - - var subCmd = &cobra.Command{ - Use: "sub [no options!]", - Short: "My subcommand", - PreRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PreRun with args: %v\n", args) - }, - Run: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd Run with args: %v\n", args) - }, - PostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PostRun with args: %v\n", args) - }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) - }, - } - - rootCmd.AddCommand(subCmd) - - rootCmd.SetArgs([]string{""}) - rootCmd.Execute() - fmt.Println() - rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) - rootCmd.Execute() -} -``` - -Output: -``` -Inside rootCmd PersistentPreRun with args: [] -Inside rootCmd PreRun with args: [] -Inside rootCmd Run with args: [] -Inside rootCmd PostRun with args: [] -Inside rootCmd PersistentPostRun with args: [] - -Inside rootCmd PersistentPreRun with args: [arg1 arg2] -Inside subCmd PreRun with args: [arg1 arg2] -Inside subCmd Run with args: [arg1 arg2] -Inside subCmd PostRun with args: [arg1 arg2] -Inside subCmd PersistentPostRun with args: [arg1 arg2] -``` - -## Suggestions when "unknown command" happens - -Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: - -``` -$ hugo srever -Error: unknown command "srever" for "hugo" - -Did you mean this? - server - -Run 'hugo --help' for usage. -``` - -Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. - -If you need to disable suggestions or tweak the string distance in your command, use: +Next, include Cobra in your application: ```go -command.DisableSuggestions = true +import "github.com/spf13/cobra" ``` -or - -```go -command.SuggestionsMinimumDistance = 1 -``` +# Usage +`cobra-cli` is a command line program to generate cobra applications and command files. +It will bootstrap your application scaffolding to rapidly +develop a Cobra-based application. It is the easiest way to incorporate Cobra into your application. -You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: +It can be installed by running: ``` -$ kubectl remove -Error: unknown command "remove" for "kubectl" - -Did you mean this? - delete - -Run 'kubectl help' for usage. +go install github.com/spf13/cobra-cli@latest ``` -## Generating documentation for your command - -Cobra can generate documentation based on subcommands, flags, etc. Read more about it in the [docs generation documentation](doc/README.md). - -## Generating shell completions +For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md) -Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md). +For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md). # License diff --git a/vendor/github.com/spf13/cobra/active_help.go b/vendor/github.com/spf13/cobra/active_help.go new file mode 100644 index 00000000000..0c631913d45 --- /dev/null +++ b/vendor/github.com/spf13/cobra/active_help.go @@ -0,0 +1,49 @@ +package cobra + +import ( + "fmt" + "os" + "strings" +) + +const ( + activeHelpMarker = "_activeHelp_ " + // The below values should not be changed: programs will be using them explicitly + // in their user documentation, and users will be using them explicitly. + activeHelpEnvVarSuffix = "_ACTIVE_HELP" + activeHelpGlobalEnvVar = "COBRA_ACTIVE_HELP" + activeHelpGlobalDisable = "0" +) + +// AppendActiveHelp adds the specified string to the specified array to be used as ActiveHelp. +// Such strings will be processed by the completion script and will be shown as ActiveHelp +// to the user. +// The array parameter should be the array that will contain the completions. +// This function can be called multiple times before and/or after completions are added to +// the array. Each time this function is called with the same array, the new +// ActiveHelp line will be shown below the previous ones when completion is triggered. +func AppendActiveHelp(compArray []string, activeHelpStr string) []string { + return append(compArray, fmt.Sprintf("%s%s", activeHelpMarker, activeHelpStr)) +} + +// GetActiveHelpConfig returns the value of the ActiveHelp environment variable +// _ACTIVE_HELP where is the name of the root command in upper +// case, with all - replaced by _. +// It will always return "0" if the global environment variable COBRA_ACTIVE_HELP +// is set to "0". +func GetActiveHelpConfig(cmd *Command) string { + activeHelpCfg := os.Getenv(activeHelpGlobalEnvVar) + if activeHelpCfg != activeHelpGlobalDisable { + activeHelpCfg = os.Getenv(activeHelpEnvVar(cmd.Root().Name())) + } + return activeHelpCfg +} + +// activeHelpEnvVar returns the name of the program-specific ActiveHelp environment +// variable. It has the format _ACTIVE_HELP where is the name of the +// root command in upper case, with all - replaced by _. +func activeHelpEnvVar(name string) string { + // This format should not be changed: users will be using it explicitly. + activeHelpEnvVar := strings.ToUpper(fmt.Sprintf("%s%s", name, activeHelpEnvVarSuffix)) + return strings.ReplaceAll(activeHelpEnvVar, "-", "_") +} diff --git a/vendor/github.com/spf13/cobra/active_help.md b/vendor/github.com/spf13/cobra/active_help.md new file mode 100644 index 00000000000..5e7f59af380 --- /dev/null +++ b/vendor/github.com/spf13/cobra/active_help.md @@ -0,0 +1,157 @@ +# Active Help + +Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion. + +For example, +``` +bash-5.1$ helm repo add [tab] +You must choose a name for the repo you are adding. + +bash-5.1$ bin/helm package [tab] +Please specify the path to the chart to package + +bash-5.1$ bin/helm package [tab][tab] +bin/ internal/ scripts/ pkg/ testdata/ +``` + +**Hint**: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program. +## Supported shells + +Active Help is currently only supported for the following shells: +- Bash (using [bash completion V2](shell_completions.md#bash-completion-v2) only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed. +- Zsh + +## Adding Active Help messages + +As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to [Shell Completions](shell_completions.md). + +Adding Active Help is done through the use of the `cobra.AppendActiveHelp(...)` function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details. + +### Active Help for nouns + +Adding Active Help when completing a noun is done within the `ValidArgsFunction(...)` of a command. Please notice the use of `cobra.AppendActiveHelp(...)` in the following example: + +```go +cmd := &cobra.Command{ + Use: "add [NAME] [URL]", + Short: "add a chart repository", + Args: require.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + return addRepo(args) + }, + ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + var comps []string + if len(args) == 0 { + comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding") + } else if len(args) == 1 { + comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding") + } else { + comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments") + } + return comps, cobra.ShellCompDirectiveNoFileComp + }, +} +``` +The example above defines the completions (none, in this specific example) as well as the Active Help messages for the `helm repo add` command. It yields the following behavior: +``` +bash-5.1$ helm repo add [tab] +You must choose a name for the repo you are adding + +bash-5.1$ helm repo add grafana [tab] +You must specify the URL for the repo you are adding + +bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab] +This command does not take any more arguments +``` +**Hint**: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions. + +### Active Help for flags + +Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example: +```go +_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) != 2 { + return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp + } + return compVersionFlag(args[1], toComplete) + }) +``` +The example above prints an Active Help message when not enough information was given by the user to complete the `--version` flag. +``` +bash-5.1$ bin/helm install myrelease --version 2.0.[tab] +You must first specify the chart to install before the --version flag can be completed + +bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab] +2.0.1 2.0.2 2.0.3 +``` + +## User control of Active Help + +You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any. +Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration. + +The way to configure Active Help is to use the program's Active Help environment +variable. That variable is named `_ACTIVE_HELP` where `` is the name of your +program in uppercase with any `-` replaced by an `_`. The variable should be set by the user to whatever +Active Help configuration values are supported by the program. + +For example, say `helm` has chosen to support three levels for Active Help: `on`, `off`, `local`. Then a user +would set the desired behavior to `local` by doing `export HELM_ACTIVE_HELP=local` in their shell. + +For simplicity, when in `cmd.ValidArgsFunction(...)` or a flag's completion function, the program should read the +Active Help configuration using the `cobra.GetActiveHelpConfig(cmd)` function and select what Active Help messages +should or should not be added (instead of reading the environment variable directly). + +For example: +```go +ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + activeHelpLevel := cobra.GetActiveHelpConfig(cmd) + + var comps []string + if len(args) == 0 { + if activeHelpLevel != "off" { + comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding") + } + } else if len(args) == 1 { + if activeHelpLevel != "off" { + comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding") + } + } else { + if activeHelpLevel == "local" { + comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments") + } + } + return comps, cobra.ShellCompDirectiveNoFileComp +}, +``` +**Note 1**: If the `_ACTIVE_HELP` environment variable is set to the string "0", Cobra will automatically disable all Active Help output (even if some output was specified by the program using the `cobra.AppendActiveHelp(...)` function). Using "0" can simplify your code in situations where you want to blindly disable Active Help without having to call `cobra.GetActiveHelpConfig(cmd)` explicitly. + +**Note 2**: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable `COBRA_ACTIVE_HELP` to "0". In this case `cobra.GetActiveHelpConfig(cmd)` will return "0" no matter what the variable `_ACTIVE_HELP` is set to. + +**Note 3**: If the user does not set `_ACTIVE_HELP` or `COBRA_ACTIVE_HELP` (which will be a common case), the default value for the Active Help configuration returned by `cobra.GetActiveHelpConfig(cmd)` will be the empty string. +## Active Help with Cobra's default completion command + +Cobra provides a default `completion` command for programs that wish to use it. +When using the default `completion` command, Active Help is configurable in the same +fashion as described above using environment variables. You may wish to document this in more +details for your users. + +## Debugging Active Help + +Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra's hidden `__complete` command. Please refer to [debugging shell completion](shell_completions.md#debugging) for details. + +When debugging with the `__complete` command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named `_ACTIVE_HELP` where any `-` is replaced by an `_`. For example, we can test deactivating some Active Help as shown below: +``` +$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h +bitnami/haproxy +bitnami/harbor +_activeHelp_ WARNING: cannot re-use a name that is still in use +:0 +Completion ended with directive: ShellCompDirectiveDefault + +$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h +bitnami/haproxy +bitnami/harbor +:0 +Completion ended with directive: ShellCompDirectiveDefault +``` diff --git a/vendor/github.com/spf13/cobra/args.go b/vendor/github.com/spf13/cobra/args.go index 70e9b262912..20a022b3084 100644 --- a/vendor/github.com/spf13/cobra/args.go +++ b/vendor/github.com/spf13/cobra/args.go @@ -107,3 +107,15 @@ func RangeArgs(min int, max int) PositionalArgs { return nil } } + +// MatchAll allows combining several PositionalArgs to work in concert. +func MatchAll(pargs ...PositionalArgs) PositionalArgs { + return func(cmd *Command, args []string) error { + for _, parg := range pargs { + if err := parg(cmd, args); err != nil { + return err + } + } + return nil + } +} diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go index 7106147937e..cb7e1953787 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.go +++ b/vendor/github.com/spf13/cobra/bash_completions.go @@ -24,7 +24,7 @@ func writePreamble(buf io.StringWriter, name string) { WriteStringAndCheck(buf, fmt.Sprintf(` __%[1]s_debug() { - if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then + if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then echo "$*" >> "${BASH_COMP_DEBUG_FILE}" fi } @@ -73,7 +73,8 @@ __%[1]s_handle_go_custom_completion() # Prepare the command to request completions for the program. # Calling ${words[0]} instead of directly %[1]s allows to handle aliases args=("${words[@]:1}") - requestComp="${words[0]} %[2]s ${args[*]}" + # Disable ActiveHelp which is not supported for bash completion v1 + requestComp="%[8]s=0 ${words[0]} %[2]s ${args[*]}" lastParam=${words[$((${#words[@]}-1))]} lastChar=${lastParam:$((${#lastParam}-1)):1} @@ -99,7 +100,7 @@ __%[1]s_handle_go_custom_completion() directive=0 fi __%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}" - __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}" + __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out}" if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then # Error code. No completion. @@ -125,7 +126,7 @@ __%[1]s_handle_go_custom_completion() local fullFilter filter filteringCmd # Do not use quotes around the $out variable or else newline # characters will be kept. - for filter in ${out[*]}; do + for filter in ${out}; do fullFilter+="$filter|" done @@ -134,9 +135,9 @@ __%[1]s_handle_go_custom_completion() $filteringCmd elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then # File completion for directories only - local subDir + local subdir # Use printf to strip any trailing newline - subdir=$(printf "%%s" "${out[0]}") + subdir=$(printf "%%s" "${out}") if [ -n "$subdir" ]; then __%[1]s_debug "Listing directories in $subdir" __%[1]s_handle_subdirs_in_dir_flag "$subdir" @@ -147,7 +148,7 @@ __%[1]s_handle_go_custom_completion() else while IFS='' read -r comp; do COMPREPLY+=("$comp") - done < <(compgen -W "${out[*]}" -- "$cur") + done < <(compgen -W "${out}" -- "$cur") fi } @@ -187,13 +188,19 @@ __%[1]s_handle_reply() PREFIX="" cur="${cur#*=}" ${flags_completion[${index}]} - if [ -n "${ZSH_VERSION}" ]; then + if [ -n "${ZSH_VERSION:-}" ]; then # zsh completion needs --flag= prefix eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )" fi fi fi - return 0; + + if [[ -z "${flag_parsing_disabled}" ]]; then + # If flag parsing is enabled, we have completed the flags and can return. + # If flag parsing is disabled, we may not know all (or any) of the flags, so we fallthrough + # to possibly call handle_go_custom_completion. + return 0; + fi ;; esac @@ -232,13 +239,13 @@ __%[1]s_handle_reply() fi if [[ ${#COMPREPLY[@]} -eq 0 ]]; then - if declare -F __%[1]s_custom_func >/dev/null; then - # try command name qualified custom func - __%[1]s_custom_func - else - # otherwise fall back to unqualified for compatibility - declare -F __custom_func >/dev/null && __custom_func - fi + if declare -F __%[1]s_custom_func >/dev/null; then + # try command name qualified custom func + __%[1]s_custom_func + else + # otherwise fall back to unqualified for compatibility + declare -F __custom_func >/dev/null && __custom_func + fi fi # available in bash-completion >= 2, not always present on macOS @@ -272,7 +279,7 @@ __%[1]s_handle_flag() # if a command required a flag, and we found it, unset must_have_one_flag() local flagname=${words[c]} - local flagvalue + local flagvalue="" # if the word contained an = if [[ ${words[c]} == *"="* ]]; then flagvalue=${flagname#*=} # take in as flagvalue after the = @@ -291,7 +298,7 @@ __%[1]s_handle_flag() # keep flag value with flagname as flaghash # flaghash variable is an associative array which is only supported in bash > 3. - if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then if [ -n "${flagvalue}" ] ; then flaghash[${flagname}]=${flagvalue} elif [ -n "${words[ $((c+1)) ]}" ] ; then @@ -303,7 +310,7 @@ __%[1]s_handle_flag() # skip the argument to a two word flag if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then - __%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" + __%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument" c=$((c+1)) # if we are looking for a flags value, don't show commands if [[ $c -eq $cword ]]; then @@ -363,7 +370,7 @@ __%[1]s_handle_word() __%[1]s_handle_command elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then # aliashash variable is an associative array which is only supported in bash > 3. - if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then + if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then words[c]=${aliashash[${words[c]}]} __%[1]s_handle_command else @@ -377,14 +384,14 @@ __%[1]s_handle_word() `, name, ShellCompNoDescRequestCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name))) } func writePostscript(buf io.StringWriter, name string) { - name = strings.Replace(name, ":", "__", -1) + name = strings.ReplaceAll(name, ":", "__") WriteStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(`{ - local cur prev words cword + local cur prev words cword split declare -A flaghash 2>/dev/null || : declare -A aliashash 2>/dev/null || : if declare -F _init_completion >/dev/null 2>&1; then @@ -394,17 +401,20 @@ func writePostscript(buf io.StringWriter, name string) { fi local c=0 + local flag_parsing_disabled= local flags=() local two_word_flags=() local local_nonpersistent_flags=() local flags_with_completion=() local flags_completion=() local commands=("%[1]s") + local command_aliases=() local must_have_one_flag=() local must_have_one_noun=() - local has_completion_function - local last_command + local has_completion_function="" + local last_command="" local nouns=() + local noun_aliases=() __%[1]s_handle_word } @@ -510,6 +520,8 @@ func writeLocalNonPersistentFlag(buf io.StringWriter, flag *pflag.Flag) { // Setup annotations for go completions for registered flags func prepareCustomAnnotationsForFlags(cmd *Command) { + flagCompletionMutex.RLock() + defer flagCompletionMutex.RUnlock() for flag := range flagCompletionFunctions { // Make sure the completion script calls the __*_go_custom_completion function for // every registered flag. We need to do this here (and not when the flag was registered @@ -531,6 +543,11 @@ func writeFlags(buf io.StringWriter, cmd *Command) { flags_completion=() `) + + if cmd.DisableFlagParsing { + WriteStringAndCheck(buf, " flag_parsing_disabled=1\n") + } + localNonPersistentFlags := cmd.LocalNonPersistentFlags() cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { if nonCompletableFlag(flag) { @@ -605,7 +622,7 @@ func writeCmdAliases(buf io.StringWriter, cmd *Command) { sort.Strings(cmd.Aliases) - WriteStringAndCheck(buf, fmt.Sprint(` if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n")) + WriteStringAndCheck(buf, fmt.Sprint(` if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then`, "\n")) for _, value := range cmd.Aliases { WriteStringAndCheck(buf, fmt.Sprintf(" command_aliases+=(%q)\n", value)) WriteStringAndCheck(buf, fmt.Sprintf(" aliashash[%q]=%q\n", value, cmd.Name())) @@ -629,8 +646,8 @@ func gen(buf io.StringWriter, cmd *Command) { gen(buf, c) } commandName := cmd.CommandPath() - commandName = strings.Replace(commandName, " ", "_", -1) - commandName = strings.Replace(commandName, ":", "__", -1) + commandName = strings.ReplaceAll(commandName, " ", "_") + commandName = strings.ReplaceAll(commandName, ":", "__") if cmd.Root() == cmd { WriteStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName)) diff --git a/vendor/github.com/spf13/cobra/bash_completions.md b/vendor/github.com/spf13/cobra/bash_completions.md index 130f99b9230..52919b2fa6d 100644 --- a/vendor/github.com/spf13/cobra/bash_completions.md +++ b/vendor/github.com/spf13/cobra/bash_completions.md @@ -6,6 +6,8 @@ Please refer to [Shell Completions](shell_completions.md) for details. For backward compatibility, Cobra still supports its legacy dynamic completion solution (described below). Unlike the `ValidArgsFunction` solution, the legacy solution will only work for Bash shell-completion and not for other shells. This legacy solution can be used along-side `ValidArgsFunction` and `RegisterFlagCompletionFunc()`, as long as both solutions are not used for the same command. This provides a path to gradually migrate from the legacy solution to the new solution. +**Note**: Cobra's default `completion` command uses bash completion V2. If you are currently using Cobra's legacy dynamic completion solution, you should not use the default `completion` command but continue using your own. + The legacy solution allows you to inject bash functions into the bash completion script. Those bash functions are responsible for providing the completion choices for your own completions. Some code that works in kubernetes: diff --git a/vendor/github.com/spf13/cobra/bash_completionsV2.go b/vendor/github.com/spf13/cobra/bash_completionsV2.go new file mode 100644 index 00000000000..767bf031200 --- /dev/null +++ b/vendor/github.com/spf13/cobra/bash_completionsV2.go @@ -0,0 +1,369 @@ +package cobra + +import ( + "bytes" + "fmt" + "io" + "os" +) + +func (c *Command) genBashCompletion(w io.Writer, includeDesc bool) error { + buf := new(bytes.Buffer) + genBashComp(buf, c.Name(), includeDesc) + _, err := buf.WriteTo(w) + return err +} + +func genBashComp(buf io.StringWriter, name string, includeDesc bool) { + compCmd := ShellCompRequestCmd + if !includeDesc { + compCmd = ShellCompNoDescRequestCmd + } + + WriteStringAndCheck(buf, fmt.Sprintf(`# bash completion V2 for %-36[1]s -*- shell-script -*- + +__%[1]s_debug() +{ + if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then + echo "$*" >> "${BASH_COMP_DEBUG_FILE}" + fi +} + +# Macs have bash3 for which the bash-completion package doesn't include +# _init_completion. This is a minimal version of that function. +__%[1]s_init_completion() +{ + COMPREPLY=() + _get_comp_words_by_ref "$@" cur prev words cword +} + +# This function calls the %[1]s program to obtain the completion +# results and the directive. It fills the 'out' and 'directive' vars. +__%[1]s_get_completion_results() { + local requestComp lastParam lastChar args + + # Prepare the command to request completions for the program. + # Calling ${words[0]} instead of directly %[1]s allows to handle aliases + args=("${words[@]:1}") + requestComp="${words[0]} %[2]s ${args[*]}" + + lastParam=${words[$((${#words[@]}-1))]} + lastChar=${lastParam:$((${#lastParam}-1)):1} + __%[1]s_debug "lastParam ${lastParam}, lastChar ${lastChar}" + + if [ -z "${cur}" ] && [ "${lastChar}" != "=" ]; then + # If the last parameter is complete (there is a space following it) + # We add an extra empty parameter so we can indicate this to the go method. + __%[1]s_debug "Adding extra empty parameter" + requestComp="${requestComp} ''" + fi + + # When completing a flag with an = (e.g., %[1]s -n=) + # bash focuses on the part after the =, so we need to remove + # the flag part from $cur + if [[ "${cur}" == -*=* ]]; then + cur="${cur#*=}" + fi + + __%[1]s_debug "Calling ${requestComp}" + # Use eval to handle any environment variables and such + out=$(eval "${requestComp}" 2>/dev/null) + + # Extract the directive integer at the very end of the output following a colon (:) + directive=${out##*:} + # Remove the directive + out=${out%%:*} + if [ "${directive}" = "${out}" ]; then + # There is not directive specified + directive=0 + fi + __%[1]s_debug "The completion directive is: ${directive}" + __%[1]s_debug "The completions are: ${out}" +} + +__%[1]s_process_completion_results() { + local shellCompDirectiveError=%[3]d + local shellCompDirectiveNoSpace=%[4]d + local shellCompDirectiveNoFileComp=%[5]d + local shellCompDirectiveFilterFileExt=%[6]d + local shellCompDirectiveFilterDirs=%[7]d + + if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then + # Error code. No completion. + __%[1]s_debug "Received error from custom completion go code" + return + else + if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then + if [[ $(type -t compopt) = "builtin" ]]; then + __%[1]s_debug "Activating no space" + compopt -o nospace + else + __%[1]s_debug "No space directive not supported in this version of bash" + fi + fi + if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then + if [[ $(type -t compopt) = "builtin" ]]; then + __%[1]s_debug "Activating no file completion" + compopt +o default + else + __%[1]s_debug "No file completion directive not supported in this version of bash" + fi + fi + fi + + # Separate activeHelp from normal completions + local completions=() + local activeHelp=() + __%[1]s_extract_activeHelp + + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then + # File extension filtering + local fullFilter filter filteringCmd + + # Do not use quotes around the $completions variable or else newline + # characters will be kept. + for filter in ${completions[*]}; do + fullFilter+="$filter|" + done + + filteringCmd="_filedir $fullFilter" + __%[1]s_debug "File filtering command: $filteringCmd" + $filteringCmd + elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then + # File completion for directories only + + # Use printf to strip any trailing newline + local subdir + subdir=$(printf "%%s" "${completions[0]}") + if [ -n "$subdir" ]; then + __%[1]s_debug "Listing directories in $subdir" + pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return + else + __%[1]s_debug "Listing directories in ." + _filedir -d + fi + else + __%[1]s_handle_completion_types + fi + + __%[1]s_handle_special_char "$cur" : + __%[1]s_handle_special_char "$cur" = + + # Print the activeHelp statements before we finish + if [ ${#activeHelp} -ne 0 ]; then + printf "\n"; + printf "%%s\n" "${activeHelp[@]}" + printf "\n" + + # The prompt format is only available from bash 4.4. + # We test if it is available before using it. + if (x=${PS1@P}) 2> /dev/null; then + printf "%%s" "${PS1@P}${COMP_LINE[@]}" + else + # Can't print the prompt. Just print the + # text the user had typed, it is workable enough. + printf "%%s" "${COMP_LINE[@]}" + fi + fi +} + +# Separate activeHelp lines from real completions. +# Fills the $activeHelp and $completions arrays. +__%[1]s_extract_activeHelp() { + local activeHelpMarker="%[8]s" + local endIndex=${#activeHelpMarker} + + while IFS='' read -r comp; do + if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then + comp=${comp:endIndex} + __%[1]s_debug "ActiveHelp found: $comp" + if [ -n "$comp" ]; then + activeHelp+=("$comp") + fi + else + # Not an activeHelp line but a normal completion + completions+=("$comp") + fi + done < <(printf "%%s\n" "${out}") +} + +__%[1]s_handle_completion_types() { + __%[1]s_debug "__%[1]s_handle_completion_types: COMP_TYPE is $COMP_TYPE" + + case $COMP_TYPE in + 37|42) + # Type: menu-complete/menu-complete-backward and insert-completions + # If the user requested inserting one completion at a time, or all + # completions at once on the command-line we must remove the descriptions. + # https://github.com/spf13/cobra/issues/1508 + local tab=$'\t' comp + while IFS='' read -r comp; do + [[ -z $comp ]] && continue + # Strip any description + comp=${comp%%%%$tab*} + # Only consider the completions that match + if [[ $comp == "$cur"* ]]; then + COMPREPLY+=("$comp") + fi + done < <(printf "%%s\n" "${completions[@]}") + ;; + + *) + # Type: complete (normal completion) + __%[1]s_handle_standard_completion_case + ;; + esac +} + +__%[1]s_handle_standard_completion_case() { + local tab=$'\t' comp + + # Short circuit to optimize if we don't have descriptions + if [[ "${completions[*]}" != *$tab* ]]; then + IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur") + return 0 + fi + + local longest=0 + local compline + # Look for the longest completion so that we can format things nicely + while IFS='' read -r compline; do + [[ -z $compline ]] && continue + # Strip any description before checking the length + comp=${compline%%%%$tab*} + # Only consider the completions that match + [[ $comp == "$cur"* ]] || continue + COMPREPLY+=("$compline") + if ((${#comp}>longest)); then + longest=${#comp} + fi + done < <(printf "%%s\n" "${completions[@]}") + + # If there is a single completion left, remove the description text + if [ ${#COMPREPLY[*]} -eq 1 ]; then + __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" + comp="${COMPREPLY[0]%%%%$tab*}" + __%[1]s_debug "Removed description from single completion, which is now: ${comp}" + COMPREPLY[0]=$comp + else # Format the descriptions + __%[1]s_format_comp_descriptions $longest + fi +} + +__%[1]s_handle_special_char() +{ + local comp="$1" + local char=$2 + if [[ "$comp" == *${char}* && "$COMP_WORDBREAKS" == *${char}* ]]; then + local word=${comp%%"${comp##*${char}}"} + local idx=${#COMPREPLY[*]} + while [[ $((--idx)) -ge 0 ]]; do + COMPREPLY[$idx]=${COMPREPLY[$idx]#"$word"} + done + fi +} + +__%[1]s_format_comp_descriptions() +{ + local tab=$'\t' + local comp desc maxdesclength + local longest=$1 + + local i ci + for ci in ${!COMPREPLY[*]}; do + comp=${COMPREPLY[ci]} + # Properly format the description string which follows a tab character if there is one + if [[ "$comp" == *$tab* ]]; then + __%[1]s_debug "Original comp: $comp" + desc=${comp#*$tab} + comp=${comp%%%%$tab*} + + # $COLUMNS stores the current shell width. + # Remove an extra 4 because we add 2 spaces and 2 parentheses. + maxdesclength=$(( COLUMNS - longest - 4 )) + + # Make sure we can fit a description of at least 8 characters + # if we are to align the descriptions. + if [[ $maxdesclength -gt 8 ]]; then + # Add the proper number of spaces to align the descriptions + for ((i = ${#comp} ; i < longest ; i++)); do + comp+=" " + done + else + # Don't pad the descriptions so we can fit more text after the completion + maxdesclength=$(( COLUMNS - ${#comp} - 4 )) + fi + + # If there is enough space for any description text, + # truncate the descriptions that are too long for the shell width + if [ $maxdesclength -gt 0 ]; then + if [ ${#desc} -gt $maxdesclength ]; then + desc=${desc:0:$(( maxdesclength - 1 ))} + desc+="…" + fi + comp+=" ($desc)" + fi + COMPREPLY[ci]=$comp + __%[1]s_debug "Final comp: $comp" + fi + done +} + +__start_%[1]s() +{ + local cur prev words cword split + + COMPREPLY=() + + # Call _init_completion from the bash-completion package + # to prepare the arguments properly + if declare -F _init_completion >/dev/null 2>&1; then + _init_completion -n "=:" || return + else + __%[1]s_init_completion -n "=:" || return + fi + + __%[1]s_debug + __%[1]s_debug "========= starting completion logic ==========" + __%[1]s_debug "cur is ${cur}, words[*] is ${words[*]}, #words[@] is ${#words[@]}, cword is $cword" + + # The user could have moved the cursor backwards on the command-line. + # We need to trigger completion from the $cword location, so we need + # to truncate the command-line ($words) up to the $cword location. + words=("${words[@]:0:$cword+1}") + __%[1]s_debug "Truncated words[*]: ${words[*]}," + + local out directive + __%[1]s_get_completion_results + __%[1]s_process_completion_results +} + +if [[ $(type -t compopt) = "builtin" ]]; then + complete -o default -F __start_%[1]s %[1]s +else + complete -o default -o nospace -F __start_%[1]s %[1]s +fi + +# ex: ts=4 sw=4 et filetype=sh +`, name, compCmd, + ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, + activeHelpMarker)) +} + +// GenBashCompletionFileV2 generates Bash completion version 2. +func (c *Command) GenBashCompletionFileV2(filename string, includeDesc bool) error { + outFile, err := os.Create(filename) + if err != nil { + return err + } + defer outFile.Close() + + return c.GenBashCompletionV2(outFile, includeDesc) +} + +// GenBashCompletionV2 generates Bash completion file version 2 +// and writes it to the passed writer. +func (c *Command) GenBashCompletionV2(w io.Writer, includeDesc bool) error { + return c.genBashCompletion(w, includeDesc) +} diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index d6732ad1154..675bb1340af 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -18,6 +18,7 @@ package cobra import ( "bytes" "context" + "errors" "fmt" "io" "os" @@ -63,9 +64,9 @@ type Command struct { // Example is examples of how to use the command. Example string - // ValidArgs is list of all valid non-flag arguments that are accepted in bash completions + // ValidArgs is list of all valid non-flag arguments that are accepted in shell completions ValidArgs []string - // ValidArgsFunction is an optional function that provides valid non-flag arguments for bash completion. + // ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion. // It is a dynamic version of using ValidArgs. // Only one of ValidArgs and ValidArgsFunction can be used for a command. ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) @@ -74,11 +75,12 @@ type Command struct { Args PositionalArgs // ArgAliases is List of aliases for ValidArgs. - // These are not suggested to the user in the bash completion, + // These are not suggested to the user in the shell completion, // but accepted if entered manually. ArgAliases []string - // BashCompletionFunction is custom functions used by the bash autocompletion generator. + // BashCompletionFunction is custom bash functions used by the legacy bash autocompletion generator. + // For portability with other shells, it is recommended to instead use ValidArgsFunction BashCompletionFunction string // Deprecated defines, if this command is deprecated and should print this string when used. @@ -165,9 +167,12 @@ type Command struct { // errWriter is a writer defined by the user that replaces stderr errWriter io.Writer - //FParseErrWhitelist flag parse errors to be ignored + // FParseErrWhitelist flag parse errors to be ignored FParseErrWhitelist FParseErrWhitelist + // CompletionOptions is a set of options to control the handling of shell completion + CompletionOptions CompletionOptions + // commandsAreSorted defines, if command slice are sorted or not. commandsAreSorted bool // commandCalledAs is the name or alias value used to call this command. @@ -220,12 +225,23 @@ type Command struct { SuggestionsMinimumDistance int } -// Context returns underlying command context. If command wasn't -// executed with ExecuteContext Context returns Background context. +// Context returns underlying command context. If command was executed +// with ExecuteContext or the context was set with SetContext, the +// previously set context will be returned. Otherwise, nil is returned. +// +// Notice that a call to Execute and ExecuteC will replace a nil context of +// a command with a context.Background, so a background context will be +// returned by Context after one of these functions has been called. func (c *Command) Context() context.Context { return c.ctx } +// SetContext sets context for the command. It is set to context.Background by default and will be overwritten by +// Command.ExecuteContext or Command.ExecuteContextC +func (c *Command) SetContext(ctx context.Context) { + c.ctx = ctx +} + // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden // particularly useful when testing. func (c *Command) SetArgs(a []string) { @@ -848,6 +864,10 @@ func (c *Command) execute(a []string) (err error) { if err := c.validateRequiredFlags(); err != nil { return err } + if err := c.validateFlagGroups(); err != nil { + return err + } + if c.RunE != nil { if err := c.RunE(c, argWoFlags); err != nil { return err @@ -884,7 +904,8 @@ func (c *Command) preRun() { } // ExecuteContext is the same as Execute(), but sets the ctx on the command. -// Retrieve ctx by calling cmd.Context() inside your *Run lifecycle functions. +// Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs +// functions. func (c *Command) ExecuteContext(ctx context.Context) error { c.ctx = ctx return c.Execute() @@ -898,6 +919,14 @@ func (c *Command) Execute() error { return err } +// ExecuteContextC is the same as ExecuteC(), but sets the ctx on the command. +// Retrieve ctx by calling cmd.Context() inside your *Run lifecycle or ValidArgs +// functions. +func (c *Command) ExecuteContextC(ctx context.Context) (*Command, error) { + c.ctx = ctx + return c.ExecuteC() +} + // ExecuteC executes the command. func (c *Command) ExecuteC() (cmd *Command, err error) { if c.ctx == nil { @@ -914,9 +943,10 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { preExecHookFn(c) } - // initialize help as the last point possible to allow for user - // overriding + // initialize help at the last point to allow for user overriding c.InitDefaultHelpCmd() + // initialize completion at the last point to allow for user overriding + c.initDefaultCompletionCmd() args := c.args @@ -925,7 +955,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { args = os.Args[1:] } - // initialize the hidden command to be used for bash completion + // initialize the hidden command to be used for shell completion c.initCompleteCmd(args) var flags []string @@ -961,7 +991,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { if err != nil { // Always show help if requested, even if SilenceErrors is in // effect - if err == flag.ErrHelp { + if errors.Is(err, flag.ErrHelp) { cmd.HelpFunc()(cmd, args) return cmd, nil } @@ -983,7 +1013,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { func (c *Command) ValidateArgs(args []string) error { if c.Args == nil { - return nil + return ArbitraryArgs(c, args) } return c.Args(c, args) } diff --git a/vendor/github.com/spf13/cobra/command_notwin.go b/vendor/github.com/spf13/cobra/command_notwin.go index 6159c1cc19d..bb5dad90b7f 100644 --- a/vendor/github.com/spf13/cobra/command_notwin.go +++ b/vendor/github.com/spf13/cobra/command_notwin.go @@ -1,3 +1,4 @@ +//go:build !windows // +build !windows package cobra diff --git a/vendor/github.com/spf13/cobra/command_win.go b/vendor/github.com/spf13/cobra/command_win.go index 8768b1736dc..a84f5a82aab 100644 --- a/vendor/github.com/spf13/cobra/command_win.go +++ b/vendor/github.com/spf13/cobra/command_win.go @@ -1,3 +1,4 @@ +//go:build windows // +build windows package cobra diff --git a/vendor/github.com/spf13/cobra/custom_completions.go b/vendor/github.com/spf13/cobra/completions.go similarity index 58% rename from vendor/github.com/spf13/cobra/custom_completions.go rename to vendor/github.com/spf13/cobra/completions.go index fa060c147be..2c24839988c 100644 --- a/vendor/github.com/spf13/cobra/custom_completions.go +++ b/vendor/github.com/spf13/cobra/completions.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "strings" + "sync" "github.com/spf13/pflag" ) @@ -17,13 +18,25 @@ const ( ShellCompNoDescRequestCmd = "__completeNoDesc" ) -// Global map of flag completion functions. +// Global map of flag completion functions. Make sure to use flagCompletionMutex before you try to read and write from it. var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){} +// lock for reading and writing from flagCompletionFunctions +var flagCompletionMutex = &sync.RWMutex{} + // ShellCompDirective is a bit map representing the different behaviors the shell // can be instructed to have once completions have been provided. type ShellCompDirective int +type flagCompError struct { + subCommand string + flagName string +} + +func (e *flagCompError) Error() string { + return "Subcommand '" + e.subCommand + "' does not support flag '" + e.flagName + "'" +} + const ( // ShellCompDirectiveError indicates an error occurred and completions should be ignored. ShellCompDirectiveError ShellCompDirective = 1 << iota @@ -34,7 +47,6 @@ const ( // ShellCompDirectiveNoFileComp indicates that the shell should not provide // file completion even when no completion is provided. - // This currently does not work for zsh or bash < 4 ShellCompDirectiveNoFileComp // ShellCompDirectiveFilterFileExt indicates that the provided completions @@ -63,12 +75,51 @@ const ( ShellCompDirectiveDefault ShellCompDirective = 0 ) +const ( + // Constants for the completion command + compCmdName = "completion" + compCmdNoDescFlagName = "no-descriptions" + compCmdNoDescFlagDesc = "disable completion descriptions" + compCmdNoDescFlagDefault = false +) + +// CompletionOptions are the options to control shell completion +type CompletionOptions struct { + // DisableDefaultCmd prevents Cobra from creating a default 'completion' command + DisableDefaultCmd bool + // DisableNoDescFlag prevents Cobra from creating the '--no-descriptions' flag + // for shells that support completion descriptions + DisableNoDescFlag bool + // DisableDescriptions turns off all completion descriptions for shells + // that support them + DisableDescriptions bool + // HiddenDefaultCmd makes the default 'completion' command hidden + HiddenDefaultCmd bool +} + +// NoFileCompletions can be used to disable file completion for commands that should +// not trigger file completions. +func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { + return nil, ShellCompDirectiveNoFileComp +} + +// FixedCompletions can be used to create a completion function which always +// returns the same results. +func FixedCompletions(choices []string, directive ShellCompDirective) func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { + return func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { + return choices, directive + } +} + // RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag. func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error { flag := c.Flag(flagName) if flag == nil { return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName) } + flagCompletionMutex.Lock() + defer flagCompletionMutex.Unlock() + if _, exists := flagCompletionFunctions[flag]; exists { return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' already registered", flagName) } @@ -127,6 +178,12 @@ func (c *Command) initCompleteCmd(args []string) { noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd) for _, comp := range completions { + if GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable { + // Remove all activeHelp entries in this case + if strings.HasPrefix(comp, activeHelpMarker) { + continue + } + } if noDescriptions { // Remove any description that may be included following a tab character. comp = strings.Split(comp, "\t")[0] @@ -149,10 +206,6 @@ func (c *Command) initCompleteCmd(args []string) { fmt.Fprintln(finalCmd.OutOrStdout(), comp) } - if directive >= shellCompDirectiveMaxValue { - directive = ShellCompDirectiveDefault - } - // As the last printout, print the completion directive for the completion script to parse. // The directive integer must be that last character following a single colon (:). // The completion script expects : @@ -189,29 +242,63 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi if c.Root().TraverseChildren { finalCmd, finalArgs, err = c.Root().Traverse(trimmedArgs) } else { - finalCmd, finalArgs, err = c.Root().Find(trimmedArgs) + // For Root commands that don't specify any value for their Args fields, when we call + // Find(), if those Root commands don't have any sub-commands, they will accept arguments. + // However, because we have added the __complete sub-command in the current code path, the + // call to Find() -> legacyArgs() will return an error if there are any arguments. + // To avoid this, we first remove the __complete command to get back to having no sub-commands. + rootCmd := c.Root() + if len(rootCmd.Commands()) == 1 { + rootCmd.RemoveCommand(c) + } + + finalCmd, finalArgs, err = rootCmd.Find(trimmedArgs) } if err != nil { // Unable to find the real command. E.g., someInvalidCmd return c, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Unable to find a command for arguments: %v", trimmedArgs) } + finalCmd.ctx = c.ctx // Check if we are doing flag value completion before parsing the flags. // This is important because if we are completing a flag value, we need to also // remove the flag name argument from the list of finalArgs or else the parsing // could fail due to an invalid value (incomplete) for the flag. - flag, finalArgs, toComplete, err := checkIfFlagCompletion(finalCmd, finalArgs, toComplete) - if err != nil { - // Error while attempting to parse flags - return finalCmd, []string{}, ShellCompDirectiveDefault, err - } + flag, finalArgs, toComplete, flagErr := checkIfFlagCompletion(finalCmd, finalArgs, toComplete) + + // Check if interspersed is false or -- was set on a previous arg. + // This works by counting the arguments. Normally -- is not counted as arg but + // if -- was already set or interspersed is false and there is already one arg then + // the extra added -- is counted as arg. + flagCompletion := true + _ = finalCmd.ParseFlags(append(finalArgs, "--")) + newArgCount := finalCmd.Flags().NArg() // Parse the flags early so we can check if required flags are set if err = finalCmd.ParseFlags(finalArgs); err != nil { return finalCmd, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) } - if flag != nil { + realArgCount := finalCmd.Flags().NArg() + if newArgCount > realArgCount { + // don't do flag completion (see above) + flagCompletion = false + } + // Error while attempting to parse flags + if flagErr != nil { + // If error type is flagCompError and we don't want flagCompletion we should ignore the error + if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) { + return finalCmd, []string{}, ShellCompDirectiveDefault, flagErr + } + } + + // We only remove the flags from the arguments if DisableFlagParsing is not set. + // This is important for commands which have requested to do their own flag completion. + if !finalCmd.DisableFlagParsing { + finalArgs = finalCmd.Flags().Args() + } + + if flag != nil && flagCompletion { // Check if we are completing a flag value subject to annotations if validExts, present := flag.Annotations[BashCompFilenameExt]; present { if len(validExts) != 0 { @@ -235,12 +322,19 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi } } + var completions []string + var directive ShellCompDirective + + // Enforce flag groups before doing flag completions + finalCmd.enforceFlagGroupsForCompletion() + + // Note that we want to perform flagname completion even if finalCmd.DisableFlagParsing==true; + // doing this allows for completion of persistent flag names even for commands that disable flag parsing. + // // When doing completion of a flag name, as soon as an argument starts with // a '-' we know it is a flag. We cannot use isFlagArg() here as it requires // the flag name to be complete - if flag == nil && len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") { - var completions []string - + if flag == nil && len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") && flagCompletion { // First check for required flags completions = completeRequireFlags(finalCmd, toComplete) @@ -267,92 +361,94 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi }) } - directive := ShellCompDirectiveNoFileComp + directive = ShellCompDirectiveNoFileComp if len(completions) == 1 && strings.HasSuffix(completions[0], "=") { // If there is a single completion, the shell usually adds a space // after the completion. We don't want that if the flag ends with an = directive = ShellCompDirectiveNoSpace } - return finalCmd, completions, directive, nil - } - // We only remove the flags from the arguments if DisableFlagParsing is not set. - // This is important for commands which have requested to do their own flag completion. - if !finalCmd.DisableFlagParsing { - finalArgs = finalCmd.Flags().Args() - } - - var completions []string - directive := ShellCompDirectiveDefault - if flag == nil { - foundLocalNonPersistentFlag := false - // If TraverseChildren is true on the root command we don't check for - // local flags because we can use a local flag on a parent command - if !finalCmd.Root().TraverseChildren { - // Check if there are any local, non-persistent flags on the command-line - localNonPersistentFlags := finalCmd.LocalNonPersistentFlags() - finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { - if localNonPersistentFlags.Lookup(flag.Name) != nil && flag.Changed { - foundLocalNonPersistentFlag = true - } - }) + if !finalCmd.DisableFlagParsing { + // If DisableFlagParsing==false, we have completed the flags as known by Cobra; + // we can return what we found. + // If DisableFlagParsing==true, Cobra may not be aware of all flags, so we + // let the logic continue to see if ValidArgsFunction needs to be called. + return finalCmd, completions, directive, nil } + } else { + directive = ShellCompDirectiveDefault + if flag == nil { + foundLocalNonPersistentFlag := false + // If TraverseChildren is true on the root command we don't check for + // local flags because we can use a local flag on a parent command + if !finalCmd.Root().TraverseChildren { + // Check if there are any local, non-persistent flags on the command-line + localNonPersistentFlags := finalCmd.LocalNonPersistentFlags() + finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) { + if localNonPersistentFlags.Lookup(flag.Name) != nil && flag.Changed { + foundLocalNonPersistentFlag = true + } + }) + } - // Complete subcommand names, including the help command - if len(finalArgs) == 0 && !foundLocalNonPersistentFlag { - // We only complete sub-commands if: - // - there are no arguments on the command-line and - // - there are no local, non-peristent flag on the command-line or TraverseChildren is true - for _, subCmd := range finalCmd.Commands() { - if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand { - if strings.HasPrefix(subCmd.Name(), toComplete) { - completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) + // Complete subcommand names, including the help command + if len(finalArgs) == 0 && !foundLocalNonPersistentFlag { + // We only complete sub-commands if: + // - there are no arguments on the command-line and + // - there are no local, non-persistent flags on the command-line or TraverseChildren is true + for _, subCmd := range finalCmd.Commands() { + if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand { + if strings.HasPrefix(subCmd.Name(), toComplete) { + completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) + } + directive = ShellCompDirectiveNoFileComp } - directive = ShellCompDirectiveNoFileComp } } - } - // Complete required flags even without the '-' prefix - completions = append(completions, completeRequireFlags(finalCmd, toComplete)...) - - // Always complete ValidArgs, even if we are completing a subcommand name. - // This is for commands that have both subcommands and ValidArgs. - if len(finalCmd.ValidArgs) > 0 { - if len(finalArgs) == 0 { - // ValidArgs are only for the first argument - for _, validArg := range finalCmd.ValidArgs { - if strings.HasPrefix(validArg, toComplete) { - completions = append(completions, validArg) + // Complete required flags even without the '-' prefix + completions = append(completions, completeRequireFlags(finalCmd, toComplete)...) + + // Always complete ValidArgs, even if we are completing a subcommand name. + // This is for commands that have both subcommands and ValidArgs. + if len(finalCmd.ValidArgs) > 0 { + if len(finalArgs) == 0 { + // ValidArgs are only for the first argument + for _, validArg := range finalCmd.ValidArgs { + if strings.HasPrefix(validArg, toComplete) { + completions = append(completions, validArg) + } } - } - directive = ShellCompDirectiveNoFileComp - - // If no completions were found within commands or ValidArgs, - // see if there are any ArgAliases that should be completed. - if len(completions) == 0 { - for _, argAlias := range finalCmd.ArgAliases { - if strings.HasPrefix(argAlias, toComplete) { - completions = append(completions, argAlias) + directive = ShellCompDirectiveNoFileComp + + // If no completions were found within commands or ValidArgs, + // see if there are any ArgAliases that should be completed. + if len(completions) == 0 { + for _, argAlias := range finalCmd.ArgAliases { + if strings.HasPrefix(argAlias, toComplete) { + completions = append(completions, argAlias) + } } } } + + // If there are ValidArgs specified (even if they don't match), we stop completion. + // Only one of ValidArgs or ValidArgsFunction can be used for a single command. + return finalCmd, completions, directive, nil } - // If there are ValidArgs specified (even if they don't match), we stop completion. - // Only one of ValidArgs or ValidArgsFunction can be used for a single command. - return finalCmd, completions, directive, nil + // Let the logic continue so as to add any ValidArgsFunction completions, + // even if we already found sub-commands. + // This is for commands that have subcommands but also specify a ValidArgsFunction. } - - // Let the logic continue so as to add any ValidArgsFunction completions, - // even if we already found sub-commands. - // This is for commands that have subcommands but also specify a ValidArgsFunction. } // Find the completion function for the flag or command var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) - if flag != nil { + if flag != nil && flagCompletion { + flagCompletionMutex.RLock() completionFn = flagCompletionFunctions[flag] + flagCompletionMutex.RUnlock() } else { completionFn = finalCmd.ValidArgsFunction } @@ -435,6 +531,7 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p var flagName string trimmedArgs := args flagWithEqual := false + orgLastArg := lastArg // When doing completion of a flag name, as soon as an argument starts with // a '-' we know it is a flag. We cannot use isFlagArg() here as that function @@ -442,7 +539,16 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p if len(lastArg) > 0 && lastArg[0] == '-' { if index := strings.Index(lastArg, "="); index >= 0 { // Flag with an = - flagName = strings.TrimLeft(lastArg[:index], "-") + if strings.HasPrefix(lastArg[:index], "--") { + // Flag has full name + flagName = lastArg[2:index] + } else { + // Flag is shorthand + // We have to get the last shorthand flag name + // e.g. `-asd` => d to provide the correct completion + // https://github.com/spf13/cobra/issues/1257 + flagName = lastArg[index-1 : index] + } lastArg = lastArg[index+1:] flagWithEqual = true } else { @@ -459,8 +565,16 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p // If the flag contains an = it means it has already been fully processed, // so we don't need to deal with it here. if index := strings.Index(prevArg, "="); index < 0 { - flagName = strings.TrimLeft(prevArg, "-") - + if strings.HasPrefix(prevArg, "--") { + // Flag has full name + flagName = prevArg[2:] + } else { + // Flag is shorthand + // We have to get the last shorthand flag name + // e.g. `-asd` => d to provide the correct completion + // https://github.com/spf13/cobra/issues/1257 + flagName = prevArg[len(prevArg)-1:] + } // Remove the uncompleted flag or else there could be an error created // for an invalid value for that flag trimmedArgs = args[:len(args)-1] @@ -476,9 +590,8 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p flag := findFlag(finalCmd, flagName) if flag == nil { - // Flag not supported by this command, nothing to complete - err := fmt.Errorf("Subcommand '%s' does not support flag '%s'", finalCmd.Name(), flagName) - return nil, nil, "", err + // Flag not supported by this command, the interspersed option might be set so return the original args + return nil, args, orgLastArg, &flagCompError{subCommand: finalCmd.Name(), flagName: flagName} } if !flagWithEqual { @@ -494,6 +607,168 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p return flag, trimmedArgs, lastArg, nil } +// initDefaultCompletionCmd adds a default 'completion' command to c. +// This function will do nothing if any of the following is true: +// 1- the feature has been explicitly disabled by the program, +// 2- c has no subcommands (to avoid creating one), +// 3- c already has a 'completion' command provided by the program. +func (c *Command) initDefaultCompletionCmd() { + if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() { + return + } + + for _, cmd := range c.commands { + if cmd.Name() == compCmdName || cmd.HasAlias(compCmdName) { + // A completion command is already available + return + } + } + + haveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions + + completionCmd := &Command{ + Use: compCmdName, + Short: "Generate the autocompletion script for the specified shell", + Long: fmt.Sprintf(`Generate the autocompletion script for %[1]s for the specified shell. +See each sub-command's help for details on how to use the generated script. +`, c.Root().Name()), + Args: NoArgs, + ValidArgsFunction: NoFileCompletions, + Hidden: c.CompletionOptions.HiddenDefaultCmd, + } + c.AddCommand(completionCmd) + + out := c.OutOrStdout() + noDesc := c.CompletionOptions.DisableDescriptions + shortDesc := "Generate the autocompletion script for %s" + bash := &Command{ + Use: "bash", + Short: fmt.Sprintf(shortDesc, "bash"), + Long: fmt.Sprintf(`Generate the autocompletion script for the bash shell. + +This script depends on the 'bash-completion' package. +If it is not installed already, you can install it via your OS's package manager. + +To load completions in your current shell session: + + source <(%[1]s completion bash) + +To load completions for every new session, execute once: + +#### Linux: + + %[1]s completion bash > /etc/bash_completion.d/%[1]s + +#### macOS: + + %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s + +You will need to start a new shell for this setup to take effect. +`, c.Root().Name()), + Args: NoArgs, + DisableFlagsInUseLine: true, + ValidArgsFunction: NoFileCompletions, + RunE: func(cmd *Command, args []string) error { + return cmd.Root().GenBashCompletionV2(out, !noDesc) + }, + } + if haveNoDescFlag { + bash.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) + } + + zsh := &Command{ + Use: "zsh", + Short: fmt.Sprintf(shortDesc, "zsh"), + Long: fmt.Sprintf(`Generate the autocompletion script for the zsh shell. + +If shell completion is not already enabled in your environment you will need +to enable it. You can execute the following once: + + echo "autoload -U compinit; compinit" >> ~/.zshrc + +To load completions in your current shell session: + + source <(%[1]s completion zsh); compdef _%[1]s %[1]s + +To load completions for every new session, execute once: + +#### Linux: + + %[1]s completion zsh > "${fpath[1]}/_%[1]s" + +#### macOS: + + %[1]s completion zsh > $(brew --prefix)/share/zsh/site-functions/_%[1]s + +You will need to start a new shell for this setup to take effect. +`, c.Root().Name()), + Args: NoArgs, + ValidArgsFunction: NoFileCompletions, + RunE: func(cmd *Command, args []string) error { + if noDesc { + return cmd.Root().GenZshCompletionNoDesc(out) + } + return cmd.Root().GenZshCompletion(out) + }, + } + if haveNoDescFlag { + zsh.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) + } + + fish := &Command{ + Use: "fish", + Short: fmt.Sprintf(shortDesc, "fish"), + Long: fmt.Sprintf(`Generate the autocompletion script for the fish shell. + +To load completions in your current shell session: + + %[1]s completion fish | source + +To load completions for every new session, execute once: + + %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish + +You will need to start a new shell for this setup to take effect. +`, c.Root().Name()), + Args: NoArgs, + ValidArgsFunction: NoFileCompletions, + RunE: func(cmd *Command, args []string) error { + return cmd.Root().GenFishCompletion(out, !noDesc) + }, + } + if haveNoDescFlag { + fish.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) + } + + powershell := &Command{ + Use: "powershell", + Short: fmt.Sprintf(shortDesc, "powershell"), + Long: fmt.Sprintf(`Generate the autocompletion script for powershell. + +To load completions in your current shell session: + + %[1]s completion powershell | Out-String | Invoke-Expression + +To load completions for every new session, add the output of the above command +to your powershell profile. +`, c.Root().Name()), + Args: NoArgs, + ValidArgsFunction: NoFileCompletions, + RunE: func(cmd *Command, args []string) error { + if noDesc { + return cmd.Root().GenPowerShellCompletion(out) + } + return cmd.Root().GenPowerShellCompletionWithDesc(out) + + }, + } + if haveNoDescFlag { + powershell.Flags().BoolVar(&noDesc, compCmdNoDescFlagName, compCmdNoDescFlagDefault, compCmdNoDescFlagDesc) + } + + completionCmd.AddCommand(bash, zsh, fish, powershell) +} + func findFlag(cmd *Command, name string) *pflag.Flag { flagSet := cmd.Flags() if len(name) == 1 { diff --git a/vendor/github.com/spf13/cobra/fish_completions.go b/vendor/github.com/spf13/cobra/fish_completions.go index 3e112347d7b..005ee6be73e 100644 --- a/vendor/github.com/spf13/cobra/fish_completions.go +++ b/vendor/github.com/spf13/cobra/fish_completions.go @@ -11,8 +11,8 @@ import ( func genFishComp(buf io.StringWriter, name string, includeDesc bool) { // Variables should not contain a '-' or ':' character nameForVar := name - nameForVar = strings.Replace(nameForVar, "-", "_", -1) - nameForVar = strings.Replace(nameForVar, ":", "_", -1) + nameForVar = strings.ReplaceAll(nameForVar, "-", "_") + nameForVar = strings.ReplaceAll(nameForVar, ":", "_") compCmd := ShellCompRequestCmd if !includeDesc { @@ -21,44 +21,48 @@ func genFishComp(buf io.StringWriter, name string, includeDesc bool) { WriteStringAndCheck(buf, fmt.Sprintf("# fish completion for %-36s -*- shell-script -*-\n", name)) WriteStringAndCheck(buf, fmt.Sprintf(` function __%[1]s_debug - set file "$BASH_COMP_DEBUG_FILE" + set -l file "$BASH_COMP_DEBUG_FILE" if test -n "$file" echo "$argv" >> $file end end function __%[1]s_perform_completion - __%[1]s_debug "Starting __%[1]s_perform_completion with: $argv" + __%[1]s_debug "Starting __%[1]s_perform_completion" - set args (string split -- " " "$argv") - set lastArg "$args[-1]" + # Extract all args except the last one + set -l args (commandline -opc) + # Extract the last arg and escape it in case it is a space + set -l lastArg (string escape -- (commandline -ct)) __%[1]s_debug "args: $args" __%[1]s_debug "last arg: $lastArg" - set emptyArg "" - if test -z "$lastArg" - __%[1]s_debug "Setting emptyArg" - set emptyArg \"\" - end - __%[1]s_debug "emptyArg: $emptyArg" - - if not type -q "$args[1]" - # This can happen when "complete --do-complete %[2]s" is called when running this script. - __%[1]s_debug "Cannot find $args[1]. No completions." - return - end + # Disable ActiveHelp which is not supported for fish shell + set -l requestComp "%[9]s=0 $args[1] %[3]s $args[2..-1] $lastArg" - set requestComp "$args[1] %[3]s $args[2..-1] $emptyArg" __%[1]s_debug "Calling $requestComp" + set -l results (eval $requestComp 2> /dev/null) + + # Some programs may output extra empty lines after the directive. + # Let's ignore them or else it will break completion. + # Ref: https://github.com/spf13/cobra/issues/1279 + for line in $results[-1..1] + if test (string trim -- $line) = "" + # Found an empty line, remove it + set results $results[1..-2] + else + # Found non-empty line, we have our proper output + break + end + end - set results (eval $requestComp 2> /dev/null) - set comps $results[1..-2] - set directiveLine $results[-1] + set -l comps $results[1..-2] + set -l directiveLine $results[-1] # For Fish, when completing a flag with an = (e.g., -n=) # completions must be prefixed with the flag - set flagPrefix (string match -r -- '-.*=' "$lastArg") + set -l flagPrefix (string match -r -- '-.*=' "$lastArg") __%[1]s_debug "Comps: $comps" __%[1]s_debug "DirectiveLine: $directiveLine" @@ -71,120 +75,129 @@ function __%[1]s_perform_completion printf "%%s\n" "$directiveLine" end -# This function does three things: -# 1- Obtain the completions and store them in the global __%[1]s_comp_results -# 2- Set the __%[1]s_comp_do_file_comp flag if file completion should be performed -# and unset it otherwise -# 3- Return true if the completion results are not empty +# This function does two things: +# - Obtain the completions and store them in the global __%[1]s_comp_results +# - Return false if file completion should be performed function __%[1]s_prepare_completions + __%[1]s_debug "" + __%[1]s_debug "========= starting completion logic ==========" + # Start fresh - set --erase __%[1]s_comp_do_file_comp set --erase __%[1]s_comp_results - # Check if the command-line is already provided. This is useful for testing. - if not set --query __%[1]s_comp_commandLine - # Use the -c flag to allow for completion in the middle of the line - set __%[1]s_comp_commandLine (commandline -c) - end - __%[1]s_debug "commandLine is: $__%[1]s_comp_commandLine" - - set results (__%[1]s_perform_completion "$__%[1]s_comp_commandLine") - set --erase __%[1]s_comp_commandLine + set -l results (__%[1]s_perform_completion) __%[1]s_debug "Completion results: $results" if test -z "$results" __%[1]s_debug "No completion, probably due to a failure" # Might as well do file completion, in case it helps - set --global __%[1]s_comp_do_file_comp 1 return 1 end - set directive (string sub --start 2 $results[-1]) + set -l directive (string sub --start 2 $results[-1]) set --global __%[1]s_comp_results $results[1..-2] __%[1]s_debug "Completions are: $__%[1]s_comp_results" __%[1]s_debug "Directive is: $directive" - set shellCompDirectiveError %[4]d - set shellCompDirectiveNoSpace %[5]d - set shellCompDirectiveNoFileComp %[6]d - set shellCompDirectiveFilterFileExt %[7]d - set shellCompDirectiveFilterDirs %[8]d + set -l shellCompDirectiveError %[4]d + set -l shellCompDirectiveNoSpace %[5]d + set -l shellCompDirectiveNoFileComp %[6]d + set -l shellCompDirectiveFilterFileExt %[7]d + set -l shellCompDirectiveFilterDirs %[8]d if test -z "$directive" set directive 0 end - set compErr (math (math --scale 0 $directive / $shellCompDirectiveError) %% 2) + set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) %% 2) if test $compErr -eq 1 __%[1]s_debug "Received error directive: aborting." # Might as well do file completion, in case it helps - set --global __%[1]s_comp_do_file_comp 1 return 1 end - set filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) %% 2) - set dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) %% 2) + set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) %% 2) + set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) %% 2) if test $filefilter -eq 1; or test $dirfilter -eq 1 __%[1]s_debug "File extension filtering or directory filtering not supported" # Do full file completion instead - set --global __%[1]s_comp_do_file_comp 1 return 1 end - set nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) %% 2) - set nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) %% 2) + set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) %% 2) + set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) %% 2) __%[1]s_debug "nospace: $nospace, nofiles: $nofiles" - # Important not to quote the variable for count to work - set numComps (count $__%[1]s_comp_results) - __%[1]s_debug "numComps: $numComps" - - if test $numComps -eq 1; and test $nospace -ne 0 - # To support the "nospace" directive we trick the shell - # by outputting an extra, longer completion. - __%[1]s_debug "Adding second completion to perform nospace directive" - set --append __%[1]s_comp_results $__%[1]s_comp_results[1]. - end - - if test $numComps -eq 0; and test $nofiles -eq 0 - __%[1]s_debug "Requesting file completion" - set --global __%[1]s_comp_do_file_comp 1 + # If we want to prevent a space, or if file completion is NOT disabled, + # we need to count the number of valid completions. + # To do so, we will filter on prefix as the completions we have received + # may not already be filtered so as to allow fish to match on different + # criteria than the prefix. + if test $nospace -ne 0; or test $nofiles -eq 0 + set -l prefix (commandline -t | string escape --style=regex) + __%[1]s_debug "prefix: $prefix" + + set -l completions (string match -r -- "^$prefix.*" $__%[1]s_comp_results) + set --global __%[1]s_comp_results $completions + __%[1]s_debug "Filtered completions are: $__%[1]s_comp_results" + + # Important not to quote the variable for count to work + set -l numComps (count $__%[1]s_comp_results) + __%[1]s_debug "numComps: $numComps" + + if test $numComps -eq 1; and test $nospace -ne 0 + # We must first split on \t to get rid of the descriptions to be + # able to check what the actual completion will be. + # We don't need descriptions anyway since there is only a single + # real completion which the shell will expand immediately. + set -l split (string split --max 1 \t $__%[1]s_comp_results[1]) + + # Fish won't add a space if the completion ends with any + # of the following characters: @=/:., + set -l lastChar (string sub -s -1 -- $split) + if not string match -r -q "[@=/:.,]" -- "$lastChar" + # In other cases, to support the "nospace" directive we trick the shell + # by outputting an extra, longer completion. + __%[1]s_debug "Adding second completion to perform nospace directive" + set --global __%[1]s_comp_results $split[1] $split[1]. + __%[1]s_debug "Completions are now: $__%[1]s_comp_results" + end + end + + if test $numComps -eq 0; and test $nofiles -eq 0 + # To be consistent with bash and zsh, we only trigger file + # completion when there are no other completions + __%[1]s_debug "Requesting file completion" + return 1 + end end - # If we don't want file completion, we must return true even if there - # are no completions found. This is because fish will perform the last - # completion command, even if its condition is false, if no other - # completion command was triggered - return (not set --query __%[1]s_comp_do_file_comp) + return 0 end # Since Fish completions are only loaded once the user triggers them, we trigger them ourselves # so we can properly delete any completions provided by another script. -# The space after the the program name is essential to trigger completion for the program -# and not completion of the program name itself. -complete --do-complete "%[2]s " > /dev/null 2>&1 -# Using '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. +# Only do this if the program can be found, or else fish may print some errors; besides, +# the existing completions will only be loaded if the program can be found. +if type -q "%[2]s" + # The space after the program name is essential to trigger completion for the program + # and not completion of the program name itself. + # Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. + complete --do-complete "%[2]s " > /dev/null 2>&1 +end # Remove any pre-existing completions for the program since we will be handling all of them. complete -c %[2]s -e -# The order in which the below two lines are defined is very important so that __%[1]s_prepare_completions -# is called first. It is __%[1]s_prepare_completions that sets up the __%[1]s_comp_do_file_comp variable. -# -# This completion will be run second as complete commands are added FILO. -# It triggers file completion choices when __%[1]s_comp_do_file_comp is set. -complete -c %[2]s -n 'set --query __%[1]s_comp_do_file_comp' - -# This completion will be run first as complete commands are added FILO. -# The call to __%[1]s_prepare_completions will setup both __%[1]s_comp_results and __%[1]s_comp_do_file_comp. -# It provides the program's completion choices. +# The call to __%[1]s_prepare_completions will setup __%[1]s_comp_results +# which provides the program's completion choices. complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results' `, nameForVar, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name))) } // GenFishCompletion generates fish completion file and writes to the passed writer. diff --git a/vendor/github.com/spf13/cobra/flag_groups.go b/vendor/github.com/spf13/cobra/flag_groups.go new file mode 100644 index 00000000000..dc78431194c --- /dev/null +++ b/vendor/github.com/spf13/cobra/flag_groups.go @@ -0,0 +1,223 @@ +// Copyright © 2022 Steve Francia . +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cobra + +import ( + "fmt" + "sort" + "strings" + + flag "github.com/spf13/pflag" +) + +const ( + requiredAsGroup = "cobra_annotation_required_if_others_set" + mutuallyExclusive = "cobra_annotation_mutually_exclusive" +) + +// MarkFlagsRequiredTogether marks the given flags with annotations so that Cobra errors +// if the command is invoked with a subset (but not all) of the given flags. +func (c *Command) MarkFlagsRequiredTogether(flagNames ...string) { + c.mergePersistentFlags() + for _, v := range flagNames { + f := c.Flags().Lookup(v) + if f == nil { + panic(fmt.Sprintf("Failed to find flag %q and mark it as being required in a flag group", v)) + } + if err := c.Flags().SetAnnotation(v, requiredAsGroup, append(f.Annotations[requiredAsGroup], strings.Join(flagNames, " "))); err != nil { + // Only errs if the flag isn't found. + panic(err) + } + } +} + +// MarkFlagsMutuallyExclusive marks the given flags with annotations so that Cobra errors +// if the command is invoked with more than one flag from the given set of flags. +func (c *Command) MarkFlagsMutuallyExclusive(flagNames ...string) { + c.mergePersistentFlags() + for _, v := range flagNames { + f := c.Flags().Lookup(v) + if f == nil { + panic(fmt.Sprintf("Failed to find flag %q and mark it as being in a mutually exclusive flag group", v)) + } + // Each time this is called is a single new entry; this allows it to be a member of multiple groups if needed. + if err := c.Flags().SetAnnotation(v, mutuallyExclusive, append(f.Annotations[mutuallyExclusive], strings.Join(flagNames, " "))); err != nil { + panic(err) + } + } +} + +// validateFlagGroups validates the mutuallyExclusive/requiredAsGroup logic and returns the +// first error encountered. +func (c *Command) validateFlagGroups() error { + if c.DisableFlagParsing { + return nil + } + + flags := c.Flags() + + // groupStatus format is the list of flags as a unique ID, + // then a map of each flag name and whether it is set or not. + groupStatus := map[string]map[string]bool{} + mutuallyExclusiveGroupStatus := map[string]map[string]bool{} + flags.VisitAll(func(pflag *flag.Flag) { + processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus) + processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus) + }) + + if err := validateRequiredFlagGroups(groupStatus); err != nil { + return err + } + if err := validateExclusiveFlagGroups(mutuallyExclusiveGroupStatus); err != nil { + return err + } + return nil +} + +func hasAllFlags(fs *flag.FlagSet, flagnames ...string) bool { + for _, fname := range flagnames { + f := fs.Lookup(fname) + if f == nil { + return false + } + } + return true +} + +func processFlagForGroupAnnotation(flags *flag.FlagSet, pflag *flag.Flag, annotation string, groupStatus map[string]map[string]bool) { + groupInfo, found := pflag.Annotations[annotation] + if found { + for _, group := range groupInfo { + if groupStatus[group] == nil { + flagnames := strings.Split(group, " ") + + // Only consider this flag group at all if all the flags are defined. + if !hasAllFlags(flags, flagnames...) { + continue + } + + groupStatus[group] = map[string]bool{} + for _, name := range flagnames { + groupStatus[group][name] = false + } + } + + groupStatus[group][pflag.Name] = pflag.Changed + } + } +} + +func validateRequiredFlagGroups(data map[string]map[string]bool) error { + keys := sortedKeys(data) + for _, flagList := range keys { + flagnameAndStatus := data[flagList] + + unset := []string{} + for flagname, isSet := range flagnameAndStatus { + if !isSet { + unset = append(unset, flagname) + } + } + if len(unset) == len(flagnameAndStatus) || len(unset) == 0 { + continue + } + + // Sort values, so they can be tested/scripted against consistently. + sort.Strings(unset) + return fmt.Errorf("if any flags in the group [%v] are set they must all be set; missing %v", flagList, unset) + } + + return nil +} + +func validateExclusiveFlagGroups(data map[string]map[string]bool) error { + keys := sortedKeys(data) + for _, flagList := range keys { + flagnameAndStatus := data[flagList] + var set []string + for flagname, isSet := range flagnameAndStatus { + if isSet { + set = append(set, flagname) + } + } + if len(set) == 0 || len(set) == 1 { + continue + } + + // Sort values, so they can be tested/scripted against consistently. + sort.Strings(set) + return fmt.Errorf("if any flags in the group [%v] are set none of the others can be; %v were all set", flagList, set) + } + return nil +} + +func sortedKeys(m map[string]map[string]bool) []string { + keys := make([]string, len(m)) + i := 0 + for k := range m { + keys[i] = k + i++ + } + sort.Strings(keys) + return keys +} + +// enforceFlagGroupsForCompletion will do the following: +// - when a flag in a group is present, other flags in the group will be marked required +// - when a flag in a mutually exclusive group is present, other flags in the group will be marked as hidden +// This allows the standard completion logic to behave appropriately for flag groups +func (c *Command) enforceFlagGroupsForCompletion() { + if c.DisableFlagParsing { + return + } + + flags := c.Flags() + groupStatus := map[string]map[string]bool{} + mutuallyExclusiveGroupStatus := map[string]map[string]bool{} + c.Flags().VisitAll(func(pflag *flag.Flag) { + processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus) + processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus) + }) + + // If a flag that is part of a group is present, we make all the other flags + // of that group required so that the shell completion suggests them automatically + for flagList, flagnameAndStatus := range groupStatus { + for _, isSet := range flagnameAndStatus { + if isSet { + // One of the flags of the group is set, mark the other ones as required + for _, fName := range strings.Split(flagList, " ") { + _ = c.MarkFlagRequired(fName) + } + } + } + } + + // If a flag that is mutually exclusive to others is present, we hide the other + // flags of that group so the shell completion does not suggest them + for flagList, flagnameAndStatus := range mutuallyExclusiveGroupStatus { + for flagName, isSet := range flagnameAndStatus { + if isSet { + // One of the flags of the mutually exclusive group is set, mark the other ones as hidden + // Don't mark the flag that is already set as hidden because it may be an + // array or slice flag and therefore must continue being suggested + for _, fName := range strings.Split(flagList, " ") { + if fName != flagName { + flag := c.Flags().Lookup(fName) + flag.Hidden = true + } + } + } + } + } +} diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go index c55be71cd14..379e7c088af 100644 --- a/vendor/github.com/spf13/cobra/powershell_completions.go +++ b/vendor/github.com/spf13/cobra/powershell_completions.go @@ -50,7 +50,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { if ($Command.Length -gt $CursorPosition) { $Command=$Command.Substring(0,$CursorPosition) } - __%[1]s_debug "Truncated command: $Command" + __%[1]s_debug "Truncated command: $Command" $ShellCompDirectiveError=%[3]d $ShellCompDirectiveNoSpace=%[4]d @@ -58,9 +58,10 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { $ShellCompDirectiveFilterFileExt=%[6]d $ShellCompDirectiveFilterDirs=%[7]d - # Prepare the command to request completions for the program. + # Prepare the command to request completions for the program. # Split the command at the first space to separate the program and arguments. $Program,$Arguments = $Command.Split(" ",2) + $RequestComp="$Program %[2]s $Arguments" __%[1]s_debug "RequestComp: $RequestComp" @@ -86,15 +87,17 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { # We add an extra empty parameter so we can indicate this to the go method. __%[1]s_debug "Adding extra empty parameter" `+" # We need to use `\"`\" to pass an empty argument a \"\" or '' does not work!!!"+` -`+" $RequestComp=\"$RequestComp\" + ' `\"`\"' "+` +`+" $RequestComp=\"$RequestComp\" + ' `\"`\"'"+` } __%[1]s_debug "Calling $RequestComp" + # First disable ActiveHelp which is not supported for Powershell + $env:%[8]s=0 + #call the command store the output in $out and redirect stderr and stdout to null # $Out is an array contains each line per element Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null - # get directive from last line [int]$Directive = $Out[-1].TrimStart(':') if ($Directive -eq "") { @@ -140,19 +143,6 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { $Space = "" } - if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { - __%[1]s_debug "ShellCompDirectiveNoFileComp is called" - - if ($Values.Length -eq 0) { - # Just print an empty string here so the - # shell does not start to complete paths. - # We cannot use CompletionResult here because - # it does not accept an empty string as argument. - "" - return - } - } - if ((($Directive -band $ShellCompDirectiveFilterFileExt) -ne 0 ) -or (($Directive -band $ShellCompDirectiveFilterDirs) -ne 0 )) { __%[1]s_debug "ShellCompDirectiveFilterFileExt ShellCompDirectiveFilterDirs are not supported" @@ -165,20 +155,33 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { # filter the result $_.Name -like "$WordToComplete*" - # Join the flag back if we have a equal sign flag + # Join the flag back if we have an equal sign flag if ( $IsEqualFlag ) { __%[1]s_debug "Join the equal sign flag back to the completion value" $_.Name = $Flag + "=" + $_.Name } } + if (($Directive -band $ShellCompDirectiveNoFileComp) -ne 0 ) { + __%[1]s_debug "ShellCompDirectiveNoFileComp is called" + + if ($Values.Length -eq 0) { + # Just print an empty string here so the + # shell does not start to complete paths. + # We cannot use CompletionResult here because + # it does not accept an empty string as argument. + "" + return + } + } + # Get the current mode $Mode = (Get-PSReadLineKeyHandler | Where-Object {$_.Key -eq "Tab" }).Function __%[1]s_debug "Mode: $Mode" $Values | ForEach-Object { - # store temporay because switch will overwrite $_ + # store temporary because switch will overwrite $_ $comp = $_ # PowerShell supports three different completion modes @@ -233,7 +236,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { Default { # Like MenuComplete but we don't want to add a space here because # the user need to press space anyway to get the completion. - # Description will not be shown because thats not possible with TabCompleteNext + # Description will not be shown because that's not possible with TabCompleteNext [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)") } } @@ -242,7 +245,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock { } `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name))) } func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error { diff --git a/vendor/github.com/spf13/cobra/projects_using_cobra.md b/vendor/github.com/spf13/cobra/projects_using_cobra.md index d98a71e36f9..ac680118eff 100644 --- a/vendor/github.com/spf13/cobra/projects_using_cobra.md +++ b/vendor/github.com/spf13/cobra/projects_using_cobra.md @@ -1,9 +1,10 @@ ## Projects using Cobra - [Arduino CLI](https://github.com/arduino/arduino-cli) -- [Bleve](http://www.blevesearch.com/) -- [CockroachDB](http://www.cockroachlabs.com/) +- [Bleve](https://blevesearch.com/) +- [CockroachDB](https://www.cockroachlabs.com/) - [Cosmos SDK](https://github.com/cosmos/cosmos-sdk) +- [Datree](https://github.com/datreeio/datree) - [Delve](https://github.com/derekparker/delve) - [Docker (distribution)](https://github.com/docker/distribution) - [Etcd](https://etcd.io/) @@ -13,26 +14,41 @@ - [Github CLI](https://github.com/cli/cli) - [GitHub Labeler](https://github.com/erdaltsksn/gh-label) - [Golangci-lint](https://golangci-lint.run) -- [GopherJS](http://www.gopherjs.org/) +- [GopherJS](https://github.com/gopherjs/gopherjs) +- [GoReleaser](https://goreleaser.com) - [Helm](https://helm.sh) - [Hugo](https://gohugo.io) +- [Infracost](https://github.com/infracost/infracost) - [Istio](https://istio.io) - [Kool](https://github.com/kool-dev/kool) -- [Kubernetes](http://kubernetes.io/) +- [Kubernetes](https://kubernetes.io/) +- [Kubescape](https://github.com/armosec/kubescape) - [Linkerd](https://linkerd.io/) - [Mattermost-server](https://github.com/mattermost/mattermost-server) +- [Mercure](https://mercure.rocks/) +- [Meroxa CLI](https://github.com/meroxa/cli) - [Metal Stack CLI](https://github.com/metal-stack/metalctl) - [Moby (former Docker)](https://github.com/moby/moby) +- [Moldy](https://github.com/Moldy-Community/moldy) +- [Multi-gitter](https://github.com/lindell/multi-gitter) - [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack) +- [nFPM](https://nfpm.goreleaser.com) - [OpenShift](https://www.openshift.com/) - [Ory Hydra](https://github.com/ory/hydra) - [Ory Kratos](https://github.com/ory/kratos) +- [Pixie](https://github.com/pixie-io/pixie) +- [Polygon Edge](https://github.com/0xPolygon/polygon-edge) - [Pouch](https://github.com/alibaba/pouch) -- [ProjectAtomic (enterprise)](http://www.projectatomic.io/) +- [ProjectAtomic (enterprise)](https://www.projectatomic.io/) - [Prototool](https://github.com/uber/prototool) +- [Pulumi](https://www.pulumi.com) +- [QRcp](https://github.com/claudiodangelis/qrcp) - [Random](https://github.com/erdaltsksn/random) - [Rclone](https://rclone.org/) +- [Scaleway CLI](https://github.com/scaleway/scaleway-cli) - [Skaffold](https://skaffold.dev/) - [Tendermint](https://github.com/tendermint/tendermint) - [Twitch CLI](https://github.com/twitchdev/twitch-cli) +- [UpCloud CLI (`upctl`)](https://github.com/UpCloudLtd/upcloud-cli) +- VMware's [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) & [Tanzu Framework](https://github.com/vmware-tanzu/tanzu-framework) - [Werf](https://werf.io/) diff --git a/vendor/github.com/spf13/cobra/shell_completions.md b/vendor/github.com/spf13/cobra/shell_completions.md index cd533ac3d44..1e2058ed625 100644 --- a/vendor/github.com/spf13/cobra/shell_completions.md +++ b/vendor/github.com/spf13/cobra/shell_completions.md @@ -7,10 +7,21 @@ The currently supported shells are: - fish - PowerShell -If you are using the generator, you can create a completion command by running +Cobra will automatically provide your program with a fully functional `completion` command, +similarly to how it provides the `help` command. + +## Creating your own completion command + +If you do not wish to use the default `completion` command, you can choose to +provide your own, which will take precedence over the default one. (This also provides +backwards-compatibility with programs that already have their own `completion` command.) + +If you are using the `cobra-cli` generator, +which can be found at [spf13/cobra-cli](https://github.com/spf13/cobra-cli), +you can create a completion command by running ```bash -cobra add completion +cobra-cli add completion ``` and then modifying the generated `cmd/completion.go` file to look something like this (writing the shell script to stdout allows the most flexible use): @@ -19,17 +30,17 @@ and then modifying the generated `cmd/completion.go` file to look something like var completionCmd = &cobra.Command{ Use: "completion [bash|zsh|fish|powershell]", Short: "Generate completion script", - Long: `To load completions: + Long: fmt.Sprintf(`To load completions: Bash: - $ source <(yourprogram completion bash) + $ source <(%[1]s completion bash) # To load completions for each session, execute once: # Linux: - $ yourprogram completion bash > /etc/bash_completion.d/yourprogram + $ %[1]s completion bash > /etc/bash_completion.d/%[1]s # macOS: - $ yourprogram completion bash > /usr/local/etc/bash_completion.d/yourprogram + $ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s Zsh: @@ -39,25 +50,25 @@ Zsh: $ echo "autoload -U compinit; compinit" >> ~/.zshrc # To load completions for each session, execute once: - $ yourprogram completion zsh > "${fpath[1]}/_yourprogram" + $ %[1]s completion zsh > "${fpath[1]}/_%[1]s" # You will need to start a new shell for this setup to take effect. fish: - $ yourprogram completion fish | source + $ %[1]s completion fish | source # To load completions for each session, execute once: - $ yourprogram completion fish > ~/.config/fish/completions/yourprogram.fish + $ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish PowerShell: - PS> yourprogram completion powershell | Out-String | Invoke-Expression + PS> %[1]s completion powershell | Out-String | Invoke-Expression # To load completions for every new session, run: - PS> yourprogram completion powershell > yourprogram.ps1 + PS> %[1]s completion powershell > %[1]s.ps1 # and source this file from your PowerShell profile. -`, +`,cmd.Root().Name()), DisableFlagsInUseLine: true, ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, Args: cobra.ExactValidArgs(1), @@ -70,7 +81,7 @@ PowerShell: case "fish": cmd.Root().GenFishCompletion(os.Stdout, true) case "powershell": - cmd.Root().GenPowerShellCompletion(os.Stdout) + cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout) } }, } @@ -78,6 +89,26 @@ PowerShell: **Note:** The cobra generator may include messages printed to stdout, for example, if the config file is loaded; this will break the auto-completion script so must be removed. +## Adapting the default completion command + +Cobra provides a few options for the default `completion` command. To configure such options you must set +the `CompletionOptions` field on the *root* command. + +To tell Cobra *not* to provide the default `completion` command: +``` +rootCmd.CompletionOptions.DisableDefaultCmd = true +``` + +To tell Cobra *not* to provide the user with the `--no-descriptions` flag to the completion sub-commands: +``` +rootCmd.CompletionOptions.DisableNoDescFlag = true +``` + +To tell Cobra to completely disable descriptions for completions: +``` +rootCmd.CompletionOptions.DisableDescriptions = true +``` + # Customizing completions The generated completion scripts will automatically handle completing commands and flags. However, you can make your completions much more powerful by providing information to complete your program's nouns and flag values. @@ -91,7 +122,7 @@ For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns Some simplified code from `kubectl get` looks like: ```go -validArgs []string = { "pod", "node", "service", "replicationcontroller" } +validArgs = []string{ "pod", "node", "service", "replicationcontroller" } cmd := &cobra.Command{ Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)", @@ -117,7 +148,7 @@ node pod replicationcontroller service If your nouns have aliases, you can define them alongside `ValidArgs` using `ArgAliases`: ```go -argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } +argAliases = []string { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" } cmd := &cobra.Command{ ... @@ -323,7 +354,10 @@ cmd.RegisterFlagCompletionFunc(flagName, func(cmd *cobra.Command, args []string, ``` ### Descriptions for completions -`zsh`, `fish` and `powershell` allow for descriptions to annotate completion choices. For commands and flags, Cobra will provide the descriptions automatically, based on usage information. For example, using zsh: +Cobra provides support for completion descriptions. Such descriptions are supported for each shell +(however, for bash, it is only available in the [completion V2 version](#bash-completion-v2)). +For commands and flags, Cobra will provide the descriptions automatically, based on usage information. +For example, using zsh: ``` $ helm s[tab] search -- search for a keyword in charts @@ -336,7 +370,7 @@ $ helm s[tab] search (search for a keyword in charts) show (show information of a chart) status (displays the status of the named release) ``` -Cobra allows you to add annotations to your own completions. Simply add the annotation text after each completion, following a `\t` separator. This technique applies to completions returned by `ValidArgs`, `ValidArgsFunction` and `RegisterFlagCompletionFunc()`. For example: +Cobra allows you to add descriptions to your own completions. Simply add the description text after each completion, following a `\t` separator. This technique applies to completions returned by `ValidArgs`, `ValidArgsFunction` and `RegisterFlagCompletionFunc()`. For example: ```go ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return []string{"harbor\tAn image registry", "thanos\tLong-term metrics"}, cobra.ShellCompDirectiveNoFileComp @@ -371,6 +405,37 @@ completion firstcommand secondcommand For backward compatibility, Cobra still supports its bash legacy dynamic completion solution. Please refer to [Bash Completions](bash_completions.md) for details. +### Bash completion V2 + +Cobra provides two versions for bash completion. The original bash completion (which started it all!) can be used by calling +`GenBashCompletion()` or `GenBashCompletionFile()`. + +A new V2 bash completion version is also available. This version can be used by calling `GenBashCompletionV2()` or +`GenBashCompletionFileV2()`. The V2 version does **not** support the legacy dynamic completion +(see [Bash Completions](bash_completions.md)) but instead works only with the Go dynamic completion +solution described in this document. +Unless your program already uses the legacy dynamic completion solution, it is recommended that you use the bash +completion V2 solution which provides the following extra features: +- Supports completion descriptions (like the other shells) +- Small completion script of less than 300 lines (v1 generates scripts of thousands of lines; `kubectl` for example has a bash v1 completion script of over 13K lines) +- Streamlined user experience thanks to a completion behavior aligned with the other shells + +`Bash` completion V2 supports descriptions for completions. When calling `GenBashCompletionV2()` or `GenBashCompletionFileV2()` +you must provide these functions with a parameter indicating if the completions should be annotated with a description; Cobra +will provide the description automatically based on usage information. You can choose to make this option configurable by +your users. + +``` +# With descriptions +$ helm s[tab][tab] +search (search for a keyword in charts) status (display the status of the named release) +show (show information of a chart) + +# Without descriptions +$ helm s[tab][tab] +search show status +``` +**Note**: Cobra's default `completion` command uses bash completion V2. If for some reason you need to use bash completion V1, you will need to implement your own `completion` command. ## Zsh completions Cobra supports native zsh completion generated from the root `cobra.Command`. diff --git a/vendor/github.com/spf13/cobra/user_guide.md b/vendor/github.com/spf13/cobra/user_guide.md new file mode 100644 index 00000000000..5a7acf88e69 --- /dev/null +++ b/vendor/github.com/spf13/cobra/user_guide.md @@ -0,0 +1,666 @@ +# User Guide + +While you are welcome to provide your own organization, typically a Cobra-based +application will follow the following organizational structure: + +``` + ▾ appName/ + ▾ cmd/ + add.go + your.go + commands.go + here.go + main.go +``` + +In a Cobra app, typically the main.go file is very bare. It serves one purpose: initializing Cobra. + +```go +package main + +import ( + "{pathToYourApp}/cmd" +) + +func main() { + cmd.Execute() +} +``` + +## Using the Cobra Generator + +Cobra-CLI is its own program that will create your application and add any +commands you want. It's the easiest way to incorporate Cobra into your application. + +For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md) + +## Using the Cobra Library + +To manually implement Cobra you need to create a bare main.go file and a rootCmd file. +You will optionally provide additional commands as you see fit. + +### Create rootCmd + +Cobra doesn't require any special constructors. Simply create your commands. + +Ideally you place this in app/cmd/root.go: + +```go +var rootCmd = &cobra.Command{ + Use: "hugo", + Short: "Hugo is a very fast static site generator", + Long: `A Fast and Flexible Static Site Generator built with + love by spf13 and friends in Go. + Complete documentation is available at https://gohugo.io/documentation/`, + Run: func(cmd *cobra.Command, args []string) { + // Do Stuff Here + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} +``` + +You will additionally define flags and handle configuration in your init() function. + +For example cmd/root.go: + +```go +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var ( + // Used for flags. + cfgFile string + userLicense string + + rootCmd = &cobra.Command{ + Use: "cobra-cli", + Short: "A generator for Cobra based Applications", + Long: `Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + } +) + +// Execute executes the root command. +func Execute() error { + return rootCmd.Execute() +} + +func init() { + cobra.OnInitialize(initConfig) + + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)") + rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution") + rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project") + rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration") + viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) + viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")) + viper.SetDefault("author", "NAME HERE ") + viper.SetDefault("license", "apache") + + rootCmd.AddCommand(addCmd) + rootCmd.AddCommand(initCmd) +} + +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + // Search config in home directory with name ".cobra" (without extension). + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName(".cobra") + } + + viper.AutomaticEnv() + + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } +} +``` + +### Create your main.go + +With the root command you need to have your main function execute it. +Execute should be run on the root for clarity, though it can be called on any command. + +In a Cobra app, typically the main.go file is very bare. It serves one purpose: to initialize Cobra. + +```go +package main + +import ( + "{pathToYourApp}/cmd" +) + +func main() { + cmd.Execute() +} +``` + +### Create additional commands + +Additional commands can be defined and typically are each given their own file +inside of the cmd/ directory. + +If you wanted to create a version command you would create cmd/version.go and +populate it with the following: + +```go +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(versionCmd) +} + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version number of Hugo", + Long: `All software has versions. This is Hugo's`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Hugo Static Site Generator v0.9 -- HEAD") + }, +} +``` + +### Returning and handling errors + +If you wish to return an error to the caller of a command, `RunE` can be used. + +```go +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(tryCmd) +} + +var tryCmd = &cobra.Command{ + Use: "try", + Short: "Try and possibly fail at something", + RunE: func(cmd *cobra.Command, args []string) error { + if err := someFunc(); err != nil { + return err + } + return nil + }, +} +``` + +The error can then be caught at the execute function call. + +## Working with Flags + +Flags provide modifiers to control how the action command operates. + +### Assign flags to a command + +Since the flags are defined and used in different locations, we need to +define a variable outside with the correct scope to assign the flag to +work with. + +```go +var Verbose bool +var Source string +``` + +There are two different approaches to assign a flag. + +### Persistent Flags + +A flag can be 'persistent', meaning that this flag will be available to the +command it's assigned to as well as every command under that command. For +global flags, assign a flag as a persistent flag on the root. + +```go +rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output") +``` + +### Local Flags + +A flag can also be assigned locally, which will only apply to that specific command. + +```go +localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from") +``` + +### Local Flag on Parent Commands + +By default, Cobra only parses local flags on the target command, and any local flags on +parent commands are ignored. By enabling `Command.TraverseChildren`, Cobra will +parse local flags on each command before executing the target command. + +```go +command := cobra.Command{ + Use: "print [OPTIONS] [COMMANDS]", + TraverseChildren: true, +} +``` + +### Bind Flags with Config + +You can also bind your flags with [viper](https://github.com/spf13/viper): +```go +var author string + +func init() { + rootCmd.PersistentFlags().StringVar(&author, "author", "YOUR NAME", "Author name for copyright attribution") + viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")) +} +``` + +In this example, the persistent flag `author` is bound with `viper`. +**Note**: the variable `author` will not be set to the value from config, +when the `--author` flag is provided by user. + +More in [viper documentation](https://github.com/spf13/viper#working-with-flags). + +### Required flags + +Flags are optional by default. If instead you wish your command to report an error +when a flag has not been set, mark it as required: +```go +rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)") +rootCmd.MarkFlagRequired("region") +``` + +Or, for persistent flags: +```go +rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (required)") +rootCmd.MarkPersistentFlagRequired("region") +``` + +### Flag Groups + +If you have different flags that must be provided together (e.g. if they provide the `--username` flag they MUST provide the `--password` flag as well) then +Cobra can enforce that requirement: +```go +rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)") +rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)") +rootCmd.MarkFlagsRequiredTogether("username", "password") +``` + +You can also prevent different flags from being provided together if they represent mutually +exclusive options such as specifying an output format as either `--json` or `--yaml` but never both: +```go +rootCmd.Flags().BoolVar(&u, "json", false, "Output in JSON") +rootCmd.Flags().BoolVar(&pw, "yaml", false, "Output in YAML") +rootCmd.MarkFlagsMutuallyExclusive("json", "yaml") +``` + +In both of these cases: + - both local and persistent flags can be used + - **NOTE:** the group is only enforced on commands where every flag is defined + - a flag may appear in multiple groups + - a group may contain any number of flags + +## Positional and Custom Arguments + +Validation of positional arguments can be specified using the `Args` field of `Command`. +If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`. + +The following validators are built in: + +- `NoArgs` - the command will report an error if there are any positional args. +- `ArbitraryArgs` - the command will accept any args. +- `OnlyValidArgs` - the command will report an error if there are any positional args that are not in the `ValidArgs` field of `Command`. +- `MinimumNArgs(int)` - the command will report an error if there are not at least N positional args. +- `MaximumNArgs(int)` - the command will report an error if there are more than N positional args. +- `ExactArgs(int)` - the command will report an error if there are not exactly N positional args. +- `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command` +- `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args. +- `MatchAll(pargs ...PositionalArgs)` - enables combining existing checks with arbitrary other checks (e.g. you want to check the ExactArgs length along with other qualities). + +An example of setting the custom validator: + +```go +var cmd = &cobra.Command{ + Short: "hello", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + return errors.New("requires a color argument") + } + if myapp.IsValidColor(args[0]) { + return nil + } + return fmt.Errorf("invalid color specified: %s", args[0]) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Hello, World!") + }, +} +``` + +## Example + +In the example below, we have defined three commands. Two are at the top level +and one (cmdTimes) is a child of one of the top commands. In this case the root +is not executable, meaning that a subcommand is required. This is accomplished +by not providing a 'Run' for the 'rootCmd'. + +We have only defined one flag for a single command. + +More documentation about flags is available at https://github.com/spf13/pflag + +```go +package main + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" +) + +func main() { + var echoTimes int + + var cmdPrint = &cobra.Command{ + Use: "print [string to print]", + Short: "Print anything to the screen", + Long: `print is for printing anything back to the screen. +For many years people have printed back to the screen.`, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Print: " + strings.Join(args, " ")) + }, + } + + var cmdEcho = &cobra.Command{ + Use: "echo [string to echo]", + Short: "Echo anything to the screen", + Long: `echo is for echoing anything back. +Echo works a lot like print, except it has a child command.`, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("Echo: " + strings.Join(args, " ")) + }, + } + + var cmdTimes = &cobra.Command{ + Use: "times [string to echo]", + Short: "Echo anything to the screen more times", + Long: `echo things multiple times back to the user by providing +a count and a string.`, + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + for i := 0; i < echoTimes; i++ { + fmt.Println("Echo: " + strings.Join(args, " ")) + } + }, + } + + cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input") + + var rootCmd = &cobra.Command{Use: "app"} + rootCmd.AddCommand(cmdPrint, cmdEcho) + cmdEcho.AddCommand(cmdTimes) + rootCmd.Execute() +} +``` + +For a more complete example of a larger application, please checkout [Hugo](https://gohugo.io/). + +## Help Command + +Cobra automatically adds a help command to your application when you have subcommands. +This will be called when a user runs 'app help'. Additionally, help will also +support all other commands as input. Say, for instance, you have a command called +'create' without any additional configuration; Cobra will work when 'app help +create' is called. Every command will automatically have the '--help' flag added. + +### Example + +The following output is automatically generated by Cobra. Nothing beyond the +command and flag definitions are needed. + + $ cobra help + + Cobra is a CLI library for Go that empowers applications. + This application is a tool to generate the needed files + to quickly create a Cobra application. + + Usage: + cobra [command] + + Available Commands: + add Add a command to a Cobra Application + help Help about any command + init Initialize a Cobra Application + + Flags: + -a, --author string author name for copyright attribution (default "YOUR NAME") + --config string config file (default is $HOME/.cobra.yaml) + -h, --help help for cobra + -l, --license string name of license for the project + --viper use Viper for configuration (default true) + + Use "cobra [command] --help" for more information about a command. + + +Help is just a command like any other. There is no special logic or behavior +around it. In fact, you can provide your own if you want. + +### Defining your own help + +You can provide your own Help command or your own template for the default command to use +with following functions: + +```go +cmd.SetHelpCommand(cmd *Command) +cmd.SetHelpFunc(f func(*Command, []string)) +cmd.SetHelpTemplate(s string) +``` + +The latter two will also apply to any children commands. + +## Usage Message + +When the user provides an invalid flag or invalid command, Cobra responds by +showing the user the 'usage'. + +### Example +You may recognize this from the help above. That's because the default help +embeds the usage as part of its output. + + $ cobra --invalid + Error: unknown flag: --invalid + Usage: + cobra [command] + + Available Commands: + add Add a command to a Cobra Application + help Help about any command + init Initialize a Cobra Application + + Flags: + -a, --author string author name for copyright attribution (default "YOUR NAME") + --config string config file (default is $HOME/.cobra.yaml) + -h, --help help for cobra + -l, --license string name of license for the project + --viper use Viper for configuration (default true) + + Use "cobra [command] --help" for more information about a command. + +### Defining your own usage +You can provide your own usage function or template for Cobra to use. +Like help, the function and template are overridable through public methods: + +```go +cmd.SetUsageFunc(f func(*Command) error) +cmd.SetUsageTemplate(s string) +``` + +## Version Flag + +Cobra adds a top-level '--version' flag if the Version field is set on the root command. +Running an application with the '--version' flag will print the version to stdout using +the version template. The template can be customized using the +`cmd.SetVersionTemplate(s string)` function. + +## PreRun and PostRun Hooks + +It is possible to run functions before or after the main `Run` function of your command. The `PersistentPreRun` and `PreRun` functions will be executed before `Run`. `PersistentPostRun` and `PostRun` will be executed after `Run`. The `Persistent*Run` functions will be inherited by children if they do not declare their own. These functions are run in the following order: + +- `PersistentPreRun` +- `PreRun` +- `Run` +- `PostRun` +- `PersistentPostRun` + +An example of two commands which use all of these features is below. When the subcommand is executed, it will run the root command's `PersistentPreRun` but not the root command's `PersistentPostRun`: + +```go +package main + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func main() { + + var rootCmd = &cobra.Command{ + Use: "root [sub]", + Short: "My root command", + PersistentPreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPreRun with args: %v\n", args) + }, + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside rootCmd PersistentPostRun with args: %v\n", args) + }, + } + + var subCmd = &cobra.Command{ + Use: "sub [no options!]", + Short: "My subcommand", + PreRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PreRun with args: %v\n", args) + }, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd Run with args: %v\n", args) + }, + PostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PostRun with args: %v\n", args) + }, + PersistentPostRun: func(cmd *cobra.Command, args []string) { + fmt.Printf("Inside subCmd PersistentPostRun with args: %v\n", args) + }, + } + + rootCmd.AddCommand(subCmd) + + rootCmd.SetArgs([]string{""}) + rootCmd.Execute() + fmt.Println() + rootCmd.SetArgs([]string{"sub", "arg1", "arg2"}) + rootCmd.Execute() +} +``` + +Output: +``` +Inside rootCmd PersistentPreRun with args: [] +Inside rootCmd PreRun with args: [] +Inside rootCmd Run with args: [] +Inside rootCmd PostRun with args: [] +Inside rootCmd PersistentPostRun with args: [] + +Inside rootCmd PersistentPreRun with args: [arg1 arg2] +Inside subCmd PreRun with args: [arg1 arg2] +Inside subCmd Run with args: [arg1 arg2] +Inside subCmd PostRun with args: [arg1 arg2] +Inside subCmd PersistentPostRun with args: [arg1 arg2] +``` + +## Suggestions when "unknown command" happens + +Cobra will print automatic suggestions when "unknown command" errors happen. This allows Cobra to behave similarly to the `git` command when a typo happens. For example: + +``` +$ hugo srever +Error: unknown command "srever" for "hugo" + +Did you mean this? + server + +Run 'hugo --help' for usage. +``` + +Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion. + +If you need to disable suggestions or tweak the string distance in your command, use: + +```go +command.DisableSuggestions = true +``` + +or + +```go +command.SuggestionsMinimumDistance = 1 +``` + +You can also explicitly set names for which a given command will be suggested using the `SuggestFor` attribute. This allows suggestions for strings that are not close in terms of string distance, but makes sense in your set of commands and for some which you don't want aliases. Example: + +``` +$ kubectl remove +Error: unknown command "remove" for "kubectl" + +Did you mean this? + delete + +Run 'kubectl help' for usage. +``` + +## Generating documentation for your command + +Cobra can generate documentation based on subcommands, flags, etc. Read more about it in the [docs generation documentation](doc/README.md). + +## Generating shell completions + +Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md). + +## Providing Active Help + +Cobra makes use of the shell-completion system to define a framework allowing you to provide Active Help to your users. Active Help are messages (hints, warnings, etc) printed as the program is being used. Read more about it in [Active Help](active_help.md). diff --git a/vendor/github.com/spf13/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go index 2e840285f38..65cd94c6040 100644 --- a/vendor/github.com/spf13/cobra/zsh_completions.go +++ b/vendor/github.com/spf13/cobra/zsh_completions.go @@ -75,7 +75,7 @@ func genZshComp(buf io.StringWriter, name string, includeDesc bool) { if !includeDesc { compCmd = ShellCompNoDescRequestCmd } - WriteStringAndCheck(buf, fmt.Sprintf(`#compdef _%[1]s %[1]s + WriteStringAndCheck(buf, fmt.Sprintf(`#compdef %[1]s # zsh completion for %-36[1]s -*- shell-script -*- @@ -95,7 +95,7 @@ _%[1]s() local shellCompDirectiveFilterFileExt=%[6]d local shellCompDirectiveFilterDirs=%[7]d - local lastParam lastChar flagPrefix requestComp out directive compCount comp lastComp + local lastParam lastChar flagPrefix requestComp out directive comp lastComp noSpace local -a completions __%[1]s_debug "\n========= starting completion logic ==========" @@ -163,8 +163,24 @@ _%[1]s() return fi - compCount=0 + local activeHelpMarker="%[8]s" + local endIndex=${#activeHelpMarker} + local startIndex=$((${#activeHelpMarker}+1)) + local hasActiveHelp=0 while IFS='\n' read -r comp; do + # Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker) + if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then + __%[1]s_debug "ActiveHelp found: $comp" + comp="${comp[$startIndex,-1]}" + if [ -n "$comp" ]; then + compadd -x "${comp}" + __%[1]s_debug "ActiveHelp will need delimiter" + hasActiveHelp=1 + fi + + continue + fi + if [ -n "$comp" ]; then # If requested, completions are returned with a description. # The description is preceded by a TAB character. @@ -172,16 +188,31 @@ _%[1]s() # We first need to escape any : as part of the completion itself. comp=${comp//:/\\:} - local tab=$(printf '\t') + local tab="$(printf '\t')" comp=${comp//$tab/:} - ((compCount++)) __%[1]s_debug "Adding completion: ${comp}" completions+=${comp} lastComp=$comp fi done < <(printf "%%s\n" "${out[@]}") + # Add a delimiter after the activeHelp statements, but only if: + # - there are completions following the activeHelp statements, or + # - file completion will be performed (so there will be choices after the activeHelp) + if [ $hasActiveHelp -eq 1 ]; then + if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then + __%[1]s_debug "Adding activeHelp delimiter" + compadd -x "--" + hasActiveHelp=0 + fi + fi + + if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then + __%[1]s_debug "Activating nospace." + noSpace="-S ''" + fi + if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then # File extension filtering local filteringCmd @@ -199,7 +230,7 @@ _%[1]s() _arguments '*:filename:'"$filteringCmd" elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then # File completion for directories only - local subDir + local subdir subdir="${completions[1]}" if [ -n "$subdir" ]; then __%[1]s_debug "Listing directories in $subdir" @@ -208,33 +239,49 @@ _%[1]s() __%[1]s_debug "Listing directories in ." fi + local result _arguments '*:dirname:_files -/'" ${flagPrefix}" + result=$? if [ -n "$subdir" ]; then popd >/dev/null 2>&1 fi - elif [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ] && [ ${compCount} -eq 1 ]; then - __%[1]s_debug "Activating nospace." - # We can use compadd here as there is no description when - # there is only one completion. - compadd -S '' "${lastComp}" - elif [ ${compCount} -eq 0 ]; then - if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then - __%[1]s_debug "deactivating file completion" + return $result + else + __%[1]s_debug "Calling _describe" + if eval _describe "completions" completions $flagPrefix $noSpace; then + __%[1]s_debug "_describe found some completions" + + # Return the success of having called _describe + return 0 else - # Perform file completion - __%[1]s_debug "activating file completion" - _arguments '*:filename:_files'" ${flagPrefix}" + __%[1]s_debug "_describe did not find completions." + __%[1]s_debug "Checking if we should do file completion." + if [ $((directive & shellCompDirectiveNoFileComp)) -ne 0 ]; then + __%[1]s_debug "deactivating file completion" + + # We must return an error code here to let zsh know that there were no + # completions found by _describe; this is what will trigger other + # matching algorithms to attempt to find completions. + # For example zsh can match letters in the middle of words. + return 1 + else + # Perform file completion + __%[1]s_debug "Activating file completion" + + # We must return the result of this command, so it must be the + # last command, or else we must store its result to return it. + _arguments '*:filename:_files'" ${flagPrefix}" + fi fi - else - _describe "completions" completions $(echo $flagPrefix) fi } # don't run the completion function when being source-ed or eval-ed if [ "$funcstack[1]" = "_%[1]s" ]; then - _%[1]s + _%[1]s fi `, name, compCmd, ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp, - ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs)) + ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, + activeHelpMarker)) } diff --git a/vendor/go.uber.org/atomic/.codecov.yml b/vendor/go.uber.org/atomic/.codecov.yml deleted file mode 100644 index 571116cc39c..00000000000 --- a/vendor/go.uber.org/atomic/.codecov.yml +++ /dev/null @@ -1,19 +0,0 @@ -coverage: - range: 80..100 - round: down - precision: 2 - - status: - project: # measuring the overall project coverage - default: # context, you can create multiple ones with custom titles - enabled: yes # must be yes|true to enable this status - target: 100 # specify the target coverage for each commit status - # option: "auto" (must increase from parent commit or pull request base) - # option: "X%" a static target percentage to hit - if_not_found: success # if parent is not found report status as success, error, or failure - if_ci_failed: error # if ci fails report status as success, error, or failure - -# Also update COVER_IGNORE_PKGS in the Makefile. -ignore: - - /internal/gen-atomicint/ - - /internal/gen-valuewrapper/ diff --git a/vendor/go.uber.org/atomic/.gitignore b/vendor/go.uber.org/atomic/.gitignore deleted file mode 100644 index c3fa253893f..00000000000 --- a/vendor/go.uber.org/atomic/.gitignore +++ /dev/null @@ -1,12 +0,0 @@ -/bin -.DS_Store -/vendor -cover.html -cover.out -lint.log - -# Binaries -*.test - -# Profiling output -*.prof diff --git a/vendor/go.uber.org/atomic/.travis.yml b/vendor/go.uber.org/atomic/.travis.yml deleted file mode 100644 index 13d0a4f2540..00000000000 --- a/vendor/go.uber.org/atomic/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -sudo: false -language: go -go_import_path: go.uber.org/atomic - -env: - global: - - GO111MODULE=on - -matrix: - include: - - go: oldstable - - go: stable - env: LINT=1 - -cache: - directories: - - vendor - -before_install: - - go version - -script: - - test -z "$LINT" || make lint - - make cover - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/go.uber.org/atomic/CHANGELOG.md b/vendor/go.uber.org/atomic/CHANGELOG.md deleted file mode 100644 index 24c0274dc32..00000000000 --- a/vendor/go.uber.org/atomic/CHANGELOG.md +++ /dev/null @@ -1,76 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [1.7.0] - 2020-09-14 -### Added -- Support JSON serialization and deserialization of primitive atomic types. -- Support Text marshalling and unmarshalling for string atomics. - -### Changed -- Disallow incorrect comparison of atomic values in a non-atomic way. - -### Removed -- Remove dependency on `golang.org/x/{lint, tools}`. - -## [1.6.0] - 2020-02-24 -### Changed -- Drop library dependency on `golang.org/x/{lint, tools}`. - -## [1.5.1] - 2019-11-19 -- Fix bug where `Bool.CAS` and `Bool.Toggle` do work correctly together - causing `CAS` to fail even though the old value matches. - -## [1.5.0] - 2019-10-29 -### Changed -- With Go modules, only the `go.uber.org/atomic` import path is supported now. - If you need to use the old import path, please add a `replace` directive to - your `go.mod`. - -## [1.4.0] - 2019-05-01 -### Added - - Add `atomic.Error` type for atomic operations on `error` values. - -## [1.3.2] - 2018-05-02 -### Added -- Add `atomic.Duration` type for atomic operations on `time.Duration` values. - -## [1.3.1] - 2017-11-14 -### Fixed -- Revert optimization for `atomic.String.Store("")` which caused data races. - -## [1.3.0] - 2017-11-13 -### Added -- Add `atomic.Bool.CAS` for compare-and-swap semantics on bools. - -### Changed -- Optimize `atomic.String.Store("")` by avoiding an allocation. - -## [1.2.0] - 2017-04-12 -### Added -- Shadow `atomic.Value` from `sync/atomic`. - -## [1.1.0] - 2017-03-10 -### Added -- Add atomic `Float64` type. - -### Changed -- Support new `go.uber.org/atomic` import path. - -## [1.0.0] - 2016-07-18 - -- Initial release. - -[1.7.0]: https://github.com/uber-go/atomic/compare/v1.6.0...v1.7.0 -[1.6.0]: https://github.com/uber-go/atomic/compare/v1.5.1...v1.6.0 -[1.5.1]: https://github.com/uber-go/atomic/compare/v1.5.0...v1.5.1 -[1.5.0]: https://github.com/uber-go/atomic/compare/v1.4.0...v1.5.0 -[1.4.0]: https://github.com/uber-go/atomic/compare/v1.3.2...v1.4.0 -[1.3.2]: https://github.com/uber-go/atomic/compare/v1.3.1...v1.3.2 -[1.3.1]: https://github.com/uber-go/atomic/compare/v1.3.0...v1.3.1 -[1.3.0]: https://github.com/uber-go/atomic/compare/v1.2.0...v1.3.0 -[1.2.0]: https://github.com/uber-go/atomic/compare/v1.1.0...v1.2.0 -[1.1.0]: https://github.com/uber-go/atomic/compare/v1.0.0...v1.1.0 -[1.0.0]: https://github.com/uber-go/atomic/releases/tag/v1.0.0 diff --git a/vendor/go.uber.org/atomic/LICENSE.txt b/vendor/go.uber.org/atomic/LICENSE.txt deleted file mode 100644 index 8765c9fbc61..00000000000 --- a/vendor/go.uber.org/atomic/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2016 Uber Technologies, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/go.uber.org/atomic/Makefile b/vendor/go.uber.org/atomic/Makefile deleted file mode 100644 index 1b1376d4253..00000000000 --- a/vendor/go.uber.org/atomic/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -# Directory to place `go install`ed binaries into. -export GOBIN ?= $(shell pwd)/bin - -GOLINT = $(GOBIN)/golint -GEN_ATOMICINT = $(GOBIN)/gen-atomicint -GEN_ATOMICWRAPPER = $(GOBIN)/gen-atomicwrapper -STATICCHECK = $(GOBIN)/staticcheck - -GO_FILES ?= $(shell find . '(' -path .git -o -path vendor ')' -prune -o -name '*.go' -print) - -# Also update ignore section in .codecov.yml. -COVER_IGNORE_PKGS = \ - go.uber.org/atomic/internal/gen-atomicint \ - go.uber.org/atomic/internal/gen-atomicwrapper - -.PHONY: build -build: - go build ./... - -.PHONY: test -test: - go test -race ./... - -.PHONY: gofmt -gofmt: - $(eval FMT_LOG := $(shell mktemp -t gofmt.XXXXX)) - gofmt -e -s -l $(GO_FILES) > $(FMT_LOG) || true - @[ ! -s "$(FMT_LOG)" ] || (echo "gofmt failed:" && cat $(FMT_LOG) && false) - -$(GOLINT): - cd tools && go install golang.org/x/lint/golint - -$(STATICCHECK): - cd tools && go install honnef.co/go/tools/cmd/staticcheck - -$(GEN_ATOMICWRAPPER): $(wildcard ./internal/gen-atomicwrapper/*) - go build -o $@ ./internal/gen-atomicwrapper - -$(GEN_ATOMICINT): $(wildcard ./internal/gen-atomicint/*) - go build -o $@ ./internal/gen-atomicint - -.PHONY: golint -golint: $(GOLINT) - $(GOLINT) ./... - -.PHONY: staticcheck -staticcheck: $(STATICCHECK) - $(STATICCHECK) ./... - -.PHONY: lint -lint: gofmt golint staticcheck generatenodirty - -# comma separated list of packages to consider for code coverage. -COVER_PKG = $(shell \ - go list -find ./... | \ - grep -v $(foreach pkg,$(COVER_IGNORE_PKGS),-e "^$(pkg)$$") | \ - paste -sd, -) - -.PHONY: cover -cover: - go test -coverprofile=cover.out -coverpkg $(COVER_PKG) -v ./... - go tool cover -html=cover.out -o cover.html - -.PHONY: generate -generate: $(GEN_ATOMICINT) $(GEN_ATOMICWRAPPER) - go generate ./... - -.PHONY: generatenodirty -generatenodirty: - @[ -z "$$(git status --porcelain)" ] || ( \ - echo "Working tree is dirty. Commit your changes first."; \ - exit 1 ) - @make generate - @status=$$(git status --porcelain); \ - [ -z "$$status" ] || ( \ - echo "Working tree is dirty after `make generate`:"; \ - echo "$$status"; \ - echo "Please ensure that the generated code is up-to-date." ) diff --git a/vendor/go.uber.org/atomic/README.md b/vendor/go.uber.org/atomic/README.md deleted file mode 100644 index ade0c20f16b..00000000000 --- a/vendor/go.uber.org/atomic/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# atomic [![GoDoc][doc-img]][doc] [![Build Status][ci-img]][ci] [![Coverage Status][cov-img]][cov] [![Go Report Card][reportcard-img]][reportcard] - -Simple wrappers for primitive types to enforce atomic access. - -## Installation - -```shell -$ go get -u go.uber.org/atomic@v1 -``` - -### Legacy Import Path - -As of v1.5.0, the import path `go.uber.org/atomic` is the only supported way -of using this package. If you are using Go modules, this package will fail to -compile with the legacy import path path `github.com/uber-go/atomic`. - -We recommend migrating your code to the new import path but if you're unable -to do so, or if your dependencies are still using the old import path, you -will have to add a `replace` directive to your `go.mod` file downgrading the -legacy import path to an older version. - -``` -replace github.com/uber-go/atomic => github.com/uber-go/atomic v1.4.0 -``` - -You can do so automatically by running the following command. - -```shell -$ go mod edit -replace github.com/uber-go/atomic=github.com/uber-go/atomic@v1.4.0 -``` - -## Usage - -The standard library's `sync/atomic` is powerful, but it's easy to forget which -variables must be accessed atomically. `go.uber.org/atomic` preserves all the -functionality of the standard library, but wraps the primitive types to -provide a safer, more convenient API. - -```go -var atom atomic.Uint32 -atom.Store(42) -atom.Sub(2) -atom.CAS(40, 11) -``` - -See the [documentation][doc] for a complete API specification. - -## Development Status - -Stable. - ---- - -Released under the [MIT License](LICENSE.txt). - -[doc-img]: https://godoc.org/github.com/uber-go/atomic?status.svg -[doc]: https://godoc.org/go.uber.org/atomic -[ci-img]: https://travis-ci.com/uber-go/atomic.svg?branch=master -[ci]: https://travis-ci.com/uber-go/atomic -[cov-img]: https://codecov.io/gh/uber-go/atomic/branch/master/graph/badge.svg -[cov]: https://codecov.io/gh/uber-go/atomic -[reportcard-img]: https://goreportcard.com/badge/go.uber.org/atomic -[reportcard]: https://goreportcard.com/report/go.uber.org/atomic diff --git a/vendor/go.uber.org/atomic/bool.go b/vendor/go.uber.org/atomic/bool.go deleted file mode 100644 index 9cf1914b1f8..00000000000 --- a/vendor/go.uber.org/atomic/bool.go +++ /dev/null @@ -1,81 +0,0 @@ -// @generated Code generated by gen-atomicwrapper. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import ( - "encoding/json" -) - -// Bool is an atomic type-safe wrapper for bool values. -type Bool struct { - _ nocmp // disallow non-atomic comparison - - v Uint32 -} - -var _zeroBool bool - -// NewBool creates a new Bool. -func NewBool(v bool) *Bool { - x := &Bool{} - if v != _zeroBool { - x.Store(v) - } - return x -} - -// Load atomically loads the wrapped bool. -func (x *Bool) Load() bool { - return truthy(x.v.Load()) -} - -// Store atomically stores the passed bool. -func (x *Bool) Store(v bool) { - x.v.Store(boolToInt(v)) -} - -// CAS is an atomic compare-and-swap for bool values. -func (x *Bool) CAS(o, n bool) bool { - return x.v.CAS(boolToInt(o), boolToInt(n)) -} - -// Swap atomically stores the given bool and returns the old -// value. -func (x *Bool) Swap(o bool) bool { - return truthy(x.v.Swap(boolToInt(o))) -} - -// MarshalJSON encodes the wrapped bool into JSON. -func (x *Bool) MarshalJSON() ([]byte, error) { - return json.Marshal(x.Load()) -} - -// UnmarshalJSON decodes a bool from JSON. -func (x *Bool) UnmarshalJSON(b []byte) error { - var v bool - if err := json.Unmarshal(b, &v); err != nil { - return err - } - x.Store(v) - return nil -} diff --git a/vendor/go.uber.org/atomic/doc.go b/vendor/go.uber.org/atomic/doc.go deleted file mode 100644 index ae7390ee688..00000000000 --- a/vendor/go.uber.org/atomic/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Package atomic provides simple wrappers around numerics to enforce atomic -// access. -package atomic diff --git a/vendor/go.uber.org/atomic/duration.go b/vendor/go.uber.org/atomic/duration.go deleted file mode 100644 index 027cfcb20bf..00000000000 --- a/vendor/go.uber.org/atomic/duration.go +++ /dev/null @@ -1,82 +0,0 @@ -// @generated Code generated by gen-atomicwrapper. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import ( - "encoding/json" - "time" -) - -// Duration is an atomic type-safe wrapper for time.Duration values. -type Duration struct { - _ nocmp // disallow non-atomic comparison - - v Int64 -} - -var _zeroDuration time.Duration - -// NewDuration creates a new Duration. -func NewDuration(v time.Duration) *Duration { - x := &Duration{} - if v != _zeroDuration { - x.Store(v) - } - return x -} - -// Load atomically loads the wrapped time.Duration. -func (x *Duration) Load() time.Duration { - return time.Duration(x.v.Load()) -} - -// Store atomically stores the passed time.Duration. -func (x *Duration) Store(v time.Duration) { - x.v.Store(int64(v)) -} - -// CAS is an atomic compare-and-swap for time.Duration values. -func (x *Duration) CAS(o, n time.Duration) bool { - return x.v.CAS(int64(o), int64(n)) -} - -// Swap atomically stores the given time.Duration and returns the old -// value. -func (x *Duration) Swap(o time.Duration) time.Duration { - return time.Duration(x.v.Swap(int64(o))) -} - -// MarshalJSON encodes the wrapped time.Duration into JSON. -func (x *Duration) MarshalJSON() ([]byte, error) { - return json.Marshal(x.Load()) -} - -// UnmarshalJSON decodes a time.Duration from JSON. -func (x *Duration) UnmarshalJSON(b []byte) error { - var v time.Duration - if err := json.Unmarshal(b, &v); err != nil { - return err - } - x.Store(v) - return nil -} diff --git a/vendor/go.uber.org/atomic/duration_ext.go b/vendor/go.uber.org/atomic/duration_ext.go deleted file mode 100644 index 6273b66bd65..00000000000 --- a/vendor/go.uber.org/atomic/duration_ext.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import "time" - -//go:generate bin/gen-atomicwrapper -name=Duration -type=time.Duration -wrapped=Int64 -pack=int64 -unpack=time.Duration -cas -swap -json -imports time -file=duration.go - -// Add atomically adds to the wrapped time.Duration and returns the new value. -func (d *Duration) Add(n time.Duration) time.Duration { - return time.Duration(d.v.Add(int64(n))) -} - -// Sub atomically subtracts from the wrapped time.Duration and returns the new value. -func (d *Duration) Sub(n time.Duration) time.Duration { - return time.Duration(d.v.Sub(int64(n))) -} - -// String encodes the wrapped value as a string. -func (d *Duration) String() string { - return d.Load().String() -} diff --git a/vendor/go.uber.org/atomic/float64.go b/vendor/go.uber.org/atomic/float64.go deleted file mode 100644 index 0719060207d..00000000000 --- a/vendor/go.uber.org/atomic/float64.go +++ /dev/null @@ -1,76 +0,0 @@ -// @generated Code generated by gen-atomicwrapper. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import ( - "encoding/json" - "math" -) - -// Float64 is an atomic type-safe wrapper for float64 values. -type Float64 struct { - _ nocmp // disallow non-atomic comparison - - v Uint64 -} - -var _zeroFloat64 float64 - -// NewFloat64 creates a new Float64. -func NewFloat64(v float64) *Float64 { - x := &Float64{} - if v != _zeroFloat64 { - x.Store(v) - } - return x -} - -// Load atomically loads the wrapped float64. -func (x *Float64) Load() float64 { - return math.Float64frombits(x.v.Load()) -} - -// Store atomically stores the passed float64. -func (x *Float64) Store(v float64) { - x.v.Store(math.Float64bits(v)) -} - -// CAS is an atomic compare-and-swap for float64 values. -func (x *Float64) CAS(o, n float64) bool { - return x.v.CAS(math.Float64bits(o), math.Float64bits(n)) -} - -// MarshalJSON encodes the wrapped float64 into JSON. -func (x *Float64) MarshalJSON() ([]byte, error) { - return json.Marshal(x.Load()) -} - -// UnmarshalJSON decodes a float64 from JSON. -func (x *Float64) UnmarshalJSON(b []byte) error { - var v float64 - if err := json.Unmarshal(b, &v); err != nil { - return err - } - x.Store(v) - return nil -} diff --git a/vendor/go.uber.org/atomic/float64_ext.go b/vendor/go.uber.org/atomic/float64_ext.go deleted file mode 100644 index 927b1add74e..00000000000 --- a/vendor/go.uber.org/atomic/float64_ext.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import "strconv" - -//go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -cas -json -imports math -file=float64.go - -// Add atomically adds to the wrapped float64 and returns the new value. -func (f *Float64) Add(s float64) float64 { - for { - old := f.Load() - new := old + s - if f.CAS(old, new) { - return new - } - } -} - -// Sub atomically subtracts from the wrapped float64 and returns the new value. -func (f *Float64) Sub(s float64) float64 { - return f.Add(-s) -} - -// String encodes the wrapped value as a string. -func (f *Float64) String() string { - // 'g' is the behavior for floats with %v. - return strconv.FormatFloat(f.Load(), 'g', -1, 64) -} diff --git a/vendor/go.uber.org/atomic/gen.go b/vendor/go.uber.org/atomic/gen.go deleted file mode 100644 index 50d6b248588..00000000000 --- a/vendor/go.uber.org/atomic/gen.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -//go:generate bin/gen-atomicint -name=Int32 -wrapped=int32 -file=int32.go -//go:generate bin/gen-atomicint -name=Int64 -wrapped=int64 -file=int64.go -//go:generate bin/gen-atomicint -name=Uint32 -wrapped=uint32 -unsigned -file=uint32.go -//go:generate bin/gen-atomicint -name=Uint64 -wrapped=uint64 -unsigned -file=uint64.go diff --git a/vendor/go.uber.org/atomic/int32.go b/vendor/go.uber.org/atomic/int32.go deleted file mode 100644 index 18ae56493ee..00000000000 --- a/vendor/go.uber.org/atomic/int32.go +++ /dev/null @@ -1,102 +0,0 @@ -// @generated Code generated by gen-atomicint. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import ( - "encoding/json" - "strconv" - "sync/atomic" -) - -// Int32 is an atomic wrapper around int32. -type Int32 struct { - _ nocmp // disallow non-atomic comparison - - v int32 -} - -// NewInt32 creates a new Int32. -func NewInt32(i int32) *Int32 { - return &Int32{v: i} -} - -// Load atomically loads the wrapped value. -func (i *Int32) Load() int32 { - return atomic.LoadInt32(&i.v) -} - -// Add atomically adds to the wrapped int32 and returns the new value. -func (i *Int32) Add(n int32) int32 { - return atomic.AddInt32(&i.v, n) -} - -// Sub atomically subtracts from the wrapped int32 and returns the new value. -func (i *Int32) Sub(n int32) int32 { - return atomic.AddInt32(&i.v, -n) -} - -// Inc atomically increments the wrapped int32 and returns the new value. -func (i *Int32) Inc() int32 { - return i.Add(1) -} - -// Dec atomically decrements the wrapped int32 and returns the new value. -func (i *Int32) Dec() int32 { - return i.Sub(1) -} - -// CAS is an atomic compare-and-swap. -func (i *Int32) CAS(old, new int32) bool { - return atomic.CompareAndSwapInt32(&i.v, old, new) -} - -// Store atomically stores the passed value. -func (i *Int32) Store(n int32) { - atomic.StoreInt32(&i.v, n) -} - -// Swap atomically swaps the wrapped int32 and returns the old value. -func (i *Int32) Swap(n int32) int32 { - return atomic.SwapInt32(&i.v, n) -} - -// MarshalJSON encodes the wrapped int32 into JSON. -func (i *Int32) MarshalJSON() ([]byte, error) { - return json.Marshal(i.Load()) -} - -// UnmarshalJSON decodes JSON into the wrapped int32. -func (i *Int32) UnmarshalJSON(b []byte) error { - var v int32 - if err := json.Unmarshal(b, &v); err != nil { - return err - } - i.Store(v) - return nil -} - -// String encodes the wrapped value as a string. -func (i *Int32) String() string { - v := i.Load() - return strconv.FormatInt(int64(v), 10) -} diff --git a/vendor/go.uber.org/atomic/int64.go b/vendor/go.uber.org/atomic/int64.go deleted file mode 100644 index 2bcbbfaa953..00000000000 --- a/vendor/go.uber.org/atomic/int64.go +++ /dev/null @@ -1,102 +0,0 @@ -// @generated Code generated by gen-atomicint. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import ( - "encoding/json" - "strconv" - "sync/atomic" -) - -// Int64 is an atomic wrapper around int64. -type Int64 struct { - _ nocmp // disallow non-atomic comparison - - v int64 -} - -// NewInt64 creates a new Int64. -func NewInt64(i int64) *Int64 { - return &Int64{v: i} -} - -// Load atomically loads the wrapped value. -func (i *Int64) Load() int64 { - return atomic.LoadInt64(&i.v) -} - -// Add atomically adds to the wrapped int64 and returns the new value. -func (i *Int64) Add(n int64) int64 { - return atomic.AddInt64(&i.v, n) -} - -// Sub atomically subtracts from the wrapped int64 and returns the new value. -func (i *Int64) Sub(n int64) int64 { - return atomic.AddInt64(&i.v, -n) -} - -// Inc atomically increments the wrapped int64 and returns the new value. -func (i *Int64) Inc() int64 { - return i.Add(1) -} - -// Dec atomically decrements the wrapped int64 and returns the new value. -func (i *Int64) Dec() int64 { - return i.Sub(1) -} - -// CAS is an atomic compare-and-swap. -func (i *Int64) CAS(old, new int64) bool { - return atomic.CompareAndSwapInt64(&i.v, old, new) -} - -// Store atomically stores the passed value. -func (i *Int64) Store(n int64) { - atomic.StoreInt64(&i.v, n) -} - -// Swap atomically swaps the wrapped int64 and returns the old value. -func (i *Int64) Swap(n int64) int64 { - return atomic.SwapInt64(&i.v, n) -} - -// MarshalJSON encodes the wrapped int64 into JSON. -func (i *Int64) MarshalJSON() ([]byte, error) { - return json.Marshal(i.Load()) -} - -// UnmarshalJSON decodes JSON into the wrapped int64. -func (i *Int64) UnmarshalJSON(b []byte) error { - var v int64 - if err := json.Unmarshal(b, &v); err != nil { - return err - } - i.Store(v) - return nil -} - -// String encodes the wrapped value as a string. -func (i *Int64) String() string { - v := i.Load() - return strconv.FormatInt(int64(v), 10) -} diff --git a/vendor/go.uber.org/atomic/nocmp.go b/vendor/go.uber.org/atomic/nocmp.go deleted file mode 100644 index a8201cb4a18..00000000000 --- a/vendor/go.uber.org/atomic/nocmp.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -// nocmp is an uncomparable struct. Embed this inside another struct to make -// it uncomparable. -// -// type Foo struct { -// nocmp -// // ... -// } -// -// This DOES NOT: -// -// - Disallow shallow copies of structs -// - Disallow comparison of pointers to uncomparable structs -type nocmp [0]func() diff --git a/vendor/go.uber.org/atomic/string.go b/vendor/go.uber.org/atomic/string.go deleted file mode 100644 index 225b7a2be0a..00000000000 --- a/vendor/go.uber.org/atomic/string.go +++ /dev/null @@ -1,54 +0,0 @@ -// @generated Code generated by gen-atomicwrapper. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -// String is an atomic type-safe wrapper for string values. -type String struct { - _ nocmp // disallow non-atomic comparison - - v Value -} - -var _zeroString string - -// NewString creates a new String. -func NewString(v string) *String { - x := &String{} - if v != _zeroString { - x.Store(v) - } - return x -} - -// Load atomically loads the wrapped string. -func (x *String) Load() string { - if v := x.v.Load(); v != nil { - return v.(string) - } - return _zeroString -} - -// Store atomically stores the passed string. -func (x *String) Store(v string) { - x.v.Store(v) -} diff --git a/vendor/go.uber.org/atomic/string_ext.go b/vendor/go.uber.org/atomic/string_ext.go deleted file mode 100644 index 3a9558213d0..00000000000 --- a/vendor/go.uber.org/atomic/string_ext.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -//go:generate bin/gen-atomicwrapper -name=String -type=string -wrapped=Value -file=string.go - -// String returns the wrapped value. -func (s *String) String() string { - return s.Load() -} - -// MarshalText encodes the wrapped string into a textual form. -// -// This makes it encodable as JSON, YAML, XML, and more. -func (s *String) MarshalText() ([]byte, error) { - return []byte(s.Load()), nil -} - -// UnmarshalText decodes text and replaces the wrapped string with it. -// -// This makes it decodable from JSON, YAML, XML, and more. -func (s *String) UnmarshalText(b []byte) error { - s.Store(string(b)) - return nil -} diff --git a/vendor/go.uber.org/atomic/uint32.go b/vendor/go.uber.org/atomic/uint32.go deleted file mode 100644 index a973aba1a60..00000000000 --- a/vendor/go.uber.org/atomic/uint32.go +++ /dev/null @@ -1,102 +0,0 @@ -// @generated Code generated by gen-atomicint. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import ( - "encoding/json" - "strconv" - "sync/atomic" -) - -// Uint32 is an atomic wrapper around uint32. -type Uint32 struct { - _ nocmp // disallow non-atomic comparison - - v uint32 -} - -// NewUint32 creates a new Uint32. -func NewUint32(i uint32) *Uint32 { - return &Uint32{v: i} -} - -// Load atomically loads the wrapped value. -func (i *Uint32) Load() uint32 { - return atomic.LoadUint32(&i.v) -} - -// Add atomically adds to the wrapped uint32 and returns the new value. -func (i *Uint32) Add(n uint32) uint32 { - return atomic.AddUint32(&i.v, n) -} - -// Sub atomically subtracts from the wrapped uint32 and returns the new value. -func (i *Uint32) Sub(n uint32) uint32 { - return atomic.AddUint32(&i.v, ^(n - 1)) -} - -// Inc atomically increments the wrapped uint32 and returns the new value. -func (i *Uint32) Inc() uint32 { - return i.Add(1) -} - -// Dec atomically decrements the wrapped uint32 and returns the new value. -func (i *Uint32) Dec() uint32 { - return i.Sub(1) -} - -// CAS is an atomic compare-and-swap. -func (i *Uint32) CAS(old, new uint32) bool { - return atomic.CompareAndSwapUint32(&i.v, old, new) -} - -// Store atomically stores the passed value. -func (i *Uint32) Store(n uint32) { - atomic.StoreUint32(&i.v, n) -} - -// Swap atomically swaps the wrapped uint32 and returns the old value. -func (i *Uint32) Swap(n uint32) uint32 { - return atomic.SwapUint32(&i.v, n) -} - -// MarshalJSON encodes the wrapped uint32 into JSON. -func (i *Uint32) MarshalJSON() ([]byte, error) { - return json.Marshal(i.Load()) -} - -// UnmarshalJSON decodes JSON into the wrapped uint32. -func (i *Uint32) UnmarshalJSON(b []byte) error { - var v uint32 - if err := json.Unmarshal(b, &v); err != nil { - return err - } - i.Store(v) - return nil -} - -// String encodes the wrapped value as a string. -func (i *Uint32) String() string { - v := i.Load() - return strconv.FormatUint(uint64(v), 10) -} diff --git a/vendor/go.uber.org/atomic/uint64.go b/vendor/go.uber.org/atomic/uint64.go deleted file mode 100644 index 3b6c71fd5a3..00000000000 --- a/vendor/go.uber.org/atomic/uint64.go +++ /dev/null @@ -1,102 +0,0 @@ -// @generated Code generated by gen-atomicint. - -// Copyright (c) 2020 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package atomic - -import ( - "encoding/json" - "strconv" - "sync/atomic" -) - -// Uint64 is an atomic wrapper around uint64. -type Uint64 struct { - _ nocmp // disallow non-atomic comparison - - v uint64 -} - -// NewUint64 creates a new Uint64. -func NewUint64(i uint64) *Uint64 { - return &Uint64{v: i} -} - -// Load atomically loads the wrapped value. -func (i *Uint64) Load() uint64 { - return atomic.LoadUint64(&i.v) -} - -// Add atomically adds to the wrapped uint64 and returns the new value. -func (i *Uint64) Add(n uint64) uint64 { - return atomic.AddUint64(&i.v, n) -} - -// Sub atomically subtracts from the wrapped uint64 and returns the new value. -func (i *Uint64) Sub(n uint64) uint64 { - return atomic.AddUint64(&i.v, ^(n - 1)) -} - -// Inc atomically increments the wrapped uint64 and returns the new value. -func (i *Uint64) Inc() uint64 { - return i.Add(1) -} - -// Dec atomically decrements the wrapped uint64 and returns the new value. -func (i *Uint64) Dec() uint64 { - return i.Sub(1) -} - -// CAS is an atomic compare-and-swap. -func (i *Uint64) CAS(old, new uint64) bool { - return atomic.CompareAndSwapUint64(&i.v, old, new) -} - -// Store atomically stores the passed value. -func (i *Uint64) Store(n uint64) { - atomic.StoreUint64(&i.v, n) -} - -// Swap atomically swaps the wrapped uint64 and returns the old value. -func (i *Uint64) Swap(n uint64) uint64 { - return atomic.SwapUint64(&i.v, n) -} - -// MarshalJSON encodes the wrapped uint64 into JSON. -func (i *Uint64) MarshalJSON() ([]byte, error) { - return json.Marshal(i.Load()) -} - -// UnmarshalJSON decodes JSON into the wrapped uint64. -func (i *Uint64) UnmarshalJSON(b []byte) error { - var v uint64 - if err := json.Unmarshal(b, &v); err != nil { - return err - } - i.Store(v) - return nil -} - -// String encodes the wrapped value as a string. -func (i *Uint64) String() string { - v := i.Load() - return strconv.FormatUint(uint64(v), 10) -} diff --git a/vendor/go.uber.org/multierr/.travis.yml b/vendor/go.uber.org/multierr/.travis.yml deleted file mode 100644 index 8636ab42ad1..00000000000 --- a/vendor/go.uber.org/multierr/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -sudo: false -language: go -go_import_path: go.uber.org/multierr - -env: - global: - - GO111MODULE=on - -go: - - oldstable - - stable - -before_install: -- go version - -script: -- | - set -e - make lint - make cover - -after_success: -- bash <(curl -s https://codecov.io/bash) diff --git a/vendor/go.uber.org/multierr/CHANGELOG.md b/vendor/go.uber.org/multierr/CHANGELOG.md index 6f1db9ef4a0..f8177b978ca 100644 --- a/vendor/go.uber.org/multierr/CHANGELOG.md +++ b/vendor/go.uber.org/multierr/CHANGELOG.md @@ -1,6 +1,41 @@ Releases ======== +v1.11.0 (2023-03-28) +==================== +- `Errors` now supports any error that implements multiple-error + interface. +- Add `Every` function to allow checking if all errors in the chain + satisfies `errors.Is` against the target error. + +v1.10.0 (2023-03-08) +==================== + +- Comply with Go 1.20's multiple-error interface. +- Drop Go 1.18 support. + Per the support policy, only Go 1.19 and 1.20 are supported now. +- Drop all non-test external dependencies. + +v1.9.0 (2022-12-12) +=================== + +- Add `AppendFunc` that allow passsing functions to similar to + `AppendInvoke`. + +- Bump up yaml.v3 dependency to 3.0.1. + +v1.8.0 (2022-02-28) +=================== + +- `Combine`: perform zero allocations when there are no errors. + + +v1.7.0 (2021-05-06) +=================== + +- Add `AppendInvoke` to append into errors from `defer` blocks. + + v1.6.0 (2020-09-14) =================== diff --git a/vendor/go.uber.org/multierr/LICENSE.txt b/vendor/go.uber.org/multierr/LICENSE.txt index 858e02475f1..413e30f7ce2 100644 --- a/vendor/go.uber.org/multierr/LICENSE.txt +++ b/vendor/go.uber.org/multierr/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2017 Uber Technologies, Inc. +Copyright (c) 2017-2021 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/go.uber.org/multierr/Makefile b/vendor/go.uber.org/multierr/Makefile index 316004400b8..dcb6fe723c0 100644 --- a/vendor/go.uber.org/multierr/Makefile +++ b/vendor/go.uber.org/multierr/Makefile @@ -34,9 +34,5 @@ lint: gofmt golint staticcheck .PHONY: cover cover: - go test -coverprofile=cover.out -coverpkg=./... -v ./... + go test -race -coverprofile=cover.out -coverpkg=./... -v ./... go tool cover -html=cover.out -o cover.html - -update-license: - @cd tools && go install go.uber.org/tools/update-license - @$(GOBIN)/update-license $(GO_FILES) diff --git a/vendor/go.uber.org/multierr/README.md b/vendor/go.uber.org/multierr/README.md index 751bd65e581..5ab6ac40f40 100644 --- a/vendor/go.uber.org/multierr/README.md +++ b/vendor/go.uber.org/multierr/README.md @@ -2,9 +2,29 @@ `multierr` allows combining one or more Go `error`s together. +## Features + +- **Idiomatic**: + multierr follows best practices in Go, and keeps your code idiomatic. + - It keeps the underlying error type hidden, + allowing you to deal in `error` values exclusively. + - It provides APIs to safely append into an error from a `defer` statement. +- **Performant**: + multierr is optimized for performance: + - It avoids allocations where possible. + - It utilizes slice resizing semantics to optimize common cases + like appending into the same error object from a loop. +- **Interoperable**: + multierr interoperates with the Go standard library's error APIs seamlessly: + - The `errors.Is` and `errors.As` functions *just work*. +- **Lightweight**: + multierr comes with virtually no dependencies. + ## Installation - go get -u go.uber.org/multierr +```bash +go get -u go.uber.org/multierr@latest +``` ## Status @@ -15,9 +35,9 @@ Stable: No breaking changes will be made before 2.0. Released under the [MIT License]. [MIT License]: LICENSE.txt -[doc-img]: https://godoc.org/go.uber.org/multierr?status.svg -[doc]: https://godoc.org/go.uber.org/multierr -[ci-img]: https://travis-ci.com/uber-go/multierr.svg?branch=master +[doc-img]: https://pkg.go.dev/badge/go.uber.org/multierr +[doc]: https://pkg.go.dev/go.uber.org/multierr +[ci-img]: https://github.com/uber-go/multierr/actions/workflows/go.yml/badge.svg [cov-img]: https://codecov.io/gh/uber-go/multierr/branch/master/graph/badge.svg -[ci]: https://travis-ci.com/uber-go/multierr +[ci]: https://github.com/uber-go/multierr/actions/workflows/go.yml [cov]: https://codecov.io/gh/uber-go/multierr diff --git a/vendor/go.uber.org/multierr/error.go b/vendor/go.uber.org/multierr/error.go index 5c9b67d5379..3a828b2dff8 100644 --- a/vendor/go.uber.org/multierr/error.go +++ b/vendor/go.uber.org/multierr/error.go @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2017-2023 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -20,54 +20,109 @@ // Package multierr allows combining one or more errors together. // -// Overview +// # Overview // // Errors can be combined with the use of the Combine function. // -// multierr.Combine( -// reader.Close(), -// writer.Close(), -// conn.Close(), -// ) +// multierr.Combine( +// reader.Close(), +// writer.Close(), +// conn.Close(), +// ) // // If only two errors are being combined, the Append function may be used // instead. // -// err = multierr.Append(reader.Close(), writer.Close()) -// -// This makes it possible to record resource cleanup failures from deferred -// blocks with the help of named return values. -// -// func sendRequest(req Request) (err error) { -// conn, err := openConnection() -// if err != nil { -// return err -// } -// defer func() { -// err = multierr.Append(err, conn.Close()) -// }() -// // ... -// } +// err = multierr.Append(reader.Close(), writer.Close()) // // The underlying list of errors for a returned error object may be retrieved // with the Errors function. // -// errors := multierr.Errors(err) -// if len(errors) > 0 { -// fmt.Println("The following errors occurred:", errors) -// } +// errors := multierr.Errors(err) +// if len(errors) > 0 { +// fmt.Println("The following errors occurred:", errors) +// } +// +// # Appending from a loop +// +// You sometimes need to append into an error from a loop. +// +// var err error +// for _, item := range items { +// err = multierr.Append(err, process(item)) +// } +// +// Cases like this may require knowledge of whether an individual instance +// failed. This usually requires introduction of a new variable. +// +// var err error +// for _, item := range items { +// if perr := process(item); perr != nil { +// log.Warn("skipping item", item) +// err = multierr.Append(err, perr) +// } +// } +// +// multierr includes AppendInto to simplify cases like this. +// +// var err error +// for _, item := range items { +// if multierr.AppendInto(&err, process(item)) { +// log.Warn("skipping item", item) +// } +// } +// +// This will append the error into the err variable, and return true if that +// individual error was non-nil. // -// Advanced Usage +// See [AppendInto] for more information. +// +// # Deferred Functions +// +// Go makes it possible to modify the return value of a function in a defer +// block if the function was using named returns. This makes it possible to +// record resource cleanup failures from deferred blocks. +// +// func sendRequest(req Request) (err error) { +// conn, err := openConnection() +// if err != nil { +// return err +// } +// defer func() { +// err = multierr.Append(err, conn.Close()) +// }() +// // ... +// } +// +// multierr provides the Invoker type and AppendInvoke function to make cases +// like the above simpler and obviate the need for a closure. The following is +// roughly equivalent to the example above. +// +// func sendRequest(req Request) (err error) { +// conn, err := openConnection() +// if err != nil { +// return err +// } +// defer multierr.AppendInvoke(&err, multierr.Close(conn)) +// // ... +// } +// +// See [AppendInvoke] and [Invoker] for more information. +// +// NOTE: If you're modifying an error from inside a defer, you MUST use a named +// return value for that function. +// +// # Advanced Usage // // Errors returned by Combine and Append MAY implement the following // interface. // -// type errorGroup interface { -// // Returns a slice containing the underlying list of errors. -// // -// // This slice MUST NOT be modified by the caller. -// Errors() []error -// } +// type errorGroup interface { +// // Returns a slice containing the underlying list of errors. +// // +// // This slice MUST NOT be modified by the caller. +// Errors() []error +// } // // Note that if you need access to list of errors behind a multierr error, you // should prefer using the Errors function. That said, if you need cheap @@ -76,23 +131,23 @@ // because errors returned by Combine and Append are not guaranteed to // implement this interface. // -// var errors []error -// group, ok := err.(errorGroup) -// if ok { -// errors = group.Errors() -// } else { -// errors = []error{err} -// } +// var errors []error +// group, ok := err.(errorGroup) +// if ok { +// errors = group.Errors() +// } else { +// errors = []error{err} +// } package multierr // import "go.uber.org/multierr" import ( "bytes" + "errors" "fmt" "io" "strings" "sync" - - "go.uber.org/atomic" + "sync/atomic" ) var ( @@ -132,34 +187,15 @@ type errorGroup interface { // Errors returns a slice containing zero or more errors that the supplied // error is composed of. If the error is nil, a nil slice is returned. // -// err := multierr.Append(r.Close(), w.Close()) -// errors := multierr.Errors(err) +// err := multierr.Append(r.Close(), w.Close()) +// errors := multierr.Errors(err) // // If the error is not composed of other errors, the returned slice contains // just the error that was passed in. // // Callers of this function are free to modify the returned slice. func Errors(err error) []error { - if err == nil { - return nil - } - - // Note that we're casting to multiError, not errorGroup. Our contract is - // that returned errors MAY implement errorGroup. Errors, however, only - // has special behavior for multierr-specific error objects. - // - // This behavior can be expanded in the future but I think it's prudent to - // start with as little as possible in terms of contract and possibility - // of misuse. - eg, ok := err.(*multiError) - if !ok { - return []error{err} - } - - errors := eg.Errors() - result := make([]error, len(errors)) - copy(result, errors) - return result + return extractErrors(err) } // multiError is an error that holds one or more errors. @@ -174,8 +210,6 @@ type multiError struct { errors []error } -var _ errorGroup = (*multiError)(nil) - // Errors returns the list of underlying errors. // // This slice MUST NOT be modified. @@ -201,6 +235,17 @@ func (merr *multiError) Error() string { return result } +// Every compares every error in the given err against the given target error +// using [errors.Is], and returns true only if every comparison returned true. +func Every(err error, target error) bool { + for _, e := range extractErrors(err) { + if !errors.Is(e, target) { + return false + } + } + return true +} + func (merr *multiError) Format(f fmt.State, c rune) { if c == 'v' && f.Flag('+') { merr.writeMultiline(f) @@ -292,6 +337,14 @@ func inspect(errors []error) (res inspectResult) { // fromSlice converts the given list of errors into a single error. func fromSlice(errors []error) error { + // Don't pay to inspect small slices. + switch len(errors) { + case 0: + return nil + case 1: + return errors[0] + } + res := inspect(errors) switch res.Count { case 0: @@ -301,8 +354,12 @@ func fromSlice(errors []error) error { return errors[res.FirstErrorIdx] case len(errors): if !res.ContainsMultiError { - // already flat - return &multiError{errors: errors} + // Error list is flat. Make a copy of it + // Otherwise "errors" escapes to the heap + // unconditionally for all other cases. + // This lets us optimize for the "no errors" case. + out := append(([]error)(nil), errors...) + return &multiError{errors: out} } } @@ -327,32 +384,32 @@ func fromSlice(errors []error) error { // If zero arguments were passed or if all items are nil, a nil error is // returned. // -// Combine(nil, nil) // == nil +// Combine(nil, nil) // == nil // // If only a single error was passed, it is returned as-is. // -// Combine(err) // == err +// Combine(err) // == err // // Combine skips over nil arguments so this function may be used to combine // together errors from operations that fail independently of each other. // -// multierr.Combine( -// reader.Close(), -// writer.Close(), -// pipe.Close(), -// ) +// multierr.Combine( +// reader.Close(), +// writer.Close(), +// pipe.Close(), +// ) // // If any of the passed errors is a multierr error, it will be flattened along // with the other errors. // -// multierr.Combine(multierr.Combine(err1, err2), err3) -// // is the same as -// multierr.Combine(err1, err2, err3) +// multierr.Combine(multierr.Combine(err1, err2), err3) +// // is the same as +// multierr.Combine(err1, err2, err3) // // The returned error formats into a readable multi-line error message if // formatted with %+v. // -// fmt.Sprintf("%+v", multierr.Combine(err1, err2)) +// fmt.Sprintf("%+v", multierr.Combine(err1, err2)) func Combine(errors ...error) error { return fromSlice(errors) } @@ -362,16 +419,19 @@ func Combine(errors ...error) error { // This function is a specialization of Combine for the common case where // there are only two errors. // -// err = multierr.Append(reader.Close(), writer.Close()) +// err = multierr.Append(reader.Close(), writer.Close()) // // The following pattern may also be used to record failure of deferred // operations without losing information about the original error. // -// func doSomething(..) (err error) { -// f := acquireResource() -// defer func() { -// err = multierr.Append(err, f.Close()) -// }() +// func doSomething(..) (err error) { +// f := acquireResource() +// defer func() { +// err = multierr.Append(err, f.Close()) +// }() +// +// Note that the variable MUST be a named return to append an error to it from +// the defer statement. See also [AppendInvoke]. func Append(left error, right error) error { switch { case left == nil: @@ -401,37 +461,37 @@ func Append(left error, right error) error { // AppendInto appends an error into the destination of an error pointer and // returns whether the error being appended was non-nil. // -// var err error -// multierr.AppendInto(&err, r.Close()) -// multierr.AppendInto(&err, w.Close()) +// var err error +// multierr.AppendInto(&err, r.Close()) +// multierr.AppendInto(&err, w.Close()) // // The above is equivalent to, // -// err := multierr.Append(r.Close(), w.Close()) +// err := multierr.Append(r.Close(), w.Close()) // // As AppendInto reports whether the provided error was non-nil, it may be // used to build a multierr error in a loop more ergonomically. For example: // -// var err error -// for line := range lines { -// var item Item -// if multierr.AppendInto(&err, parse(line, &item)) { -// continue -// } -// items = append(items, item) -// } -// -// Compare this with a verison that relies solely on Append: -// -// var err error -// for line := range lines { -// var item Item -// if parseErr := parse(line, &item); parseErr != nil { -// err = multierr.Append(err, parseErr) -// continue -// } -// items = append(items, item) -// } +// var err error +// for line := range lines { +// var item Item +// if multierr.AppendInto(&err, parse(line, &item)) { +// continue +// } +// items = append(items, item) +// } +// +// Compare this with a version that relies solely on Append: +// +// var err error +// for line := range lines { +// var item Item +// if parseErr := parse(line, &item); parseErr != nil { +// err = multierr.Append(err, parseErr) +// continue +// } +// items = append(items, item) +// } func AppendInto(into *error, err error) (errored bool) { if into == nil { // We panic if 'into' is nil. This is not documented above @@ -447,3 +507,140 @@ func AppendInto(into *error, err error) (errored bool) { *into = Append(*into, err) return true } + +// Invoker is an operation that may fail with an error. Use it with +// AppendInvoke to append the result of calling the function into an error. +// This allows you to conveniently defer capture of failing operations. +// +// See also, [Close] and [Invoke]. +type Invoker interface { + Invoke() error +} + +// Invoke wraps a function which may fail with an error to match the Invoker +// interface. Use it to supply functions matching this signature to +// AppendInvoke. +// +// For example, +// +// func processReader(r io.Reader) (err error) { +// scanner := bufio.NewScanner(r) +// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err)) +// for scanner.Scan() { +// // ... +// } +// // ... +// } +// +// In this example, the following line will construct the Invoker right away, +// but defer the invocation of scanner.Err() until the function returns. +// +// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err)) +// +// Note that the error you're appending to from the defer statement MUST be a +// named return. +type Invoke func() error + +// Invoke calls the supplied function and returns its result. +func (i Invoke) Invoke() error { return i() } + +// Close builds an Invoker that closes the provided io.Closer. Use it with +// AppendInvoke to close io.Closers and append their results into an error. +// +// For example, +// +// func processFile(path string) (err error) { +// f, err := os.Open(path) +// if err != nil { +// return err +// } +// defer multierr.AppendInvoke(&err, multierr.Close(f)) +// return processReader(f) +// } +// +// In this example, multierr.Close will construct the Invoker right away, but +// defer the invocation of f.Close until the function returns. +// +// defer multierr.AppendInvoke(&err, multierr.Close(f)) +// +// Note that the error you're appending to from the defer statement MUST be a +// named return. +func Close(closer io.Closer) Invoker { + return Invoke(closer.Close) +} + +// AppendInvoke appends the result of calling the given Invoker into the +// provided error pointer. Use it with named returns to safely defer +// invocation of fallible operations until a function returns, and capture the +// resulting errors. +// +// func doSomething(...) (err error) { +// // ... +// f, err := openFile(..) +// if err != nil { +// return err +// } +// +// // multierr will call f.Close() when this function returns and +// // if the operation fails, its append its error into the +// // returned error. +// defer multierr.AppendInvoke(&err, multierr.Close(f)) +// +// scanner := bufio.NewScanner(f) +// // Similarly, this scheduled scanner.Err to be called and +// // inspected when the function returns and append its error +// // into the returned error. +// defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err)) +// +// // ... +// } +// +// NOTE: If used with a defer, the error variable MUST be a named return. +// +// Without defer, AppendInvoke behaves exactly like AppendInto. +// +// err := // ... +// multierr.AppendInvoke(&err, mutltierr.Invoke(foo)) +// +// // ...is roughly equivalent to... +// +// err := // ... +// multierr.AppendInto(&err, foo()) +// +// The advantage of the indirection introduced by Invoker is to make it easy +// to defer the invocation of a function. Without this indirection, the +// invoked function will be evaluated at the time of the defer block rather +// than when the function returns. +// +// // BAD: This is likely not what the caller intended. This will evaluate +// // foo() right away and append its result into the error when the +// // function returns. +// defer multierr.AppendInto(&err, foo()) +// +// // GOOD: This will defer invocation of foo unutil the function returns. +// defer multierr.AppendInvoke(&err, multierr.Invoke(foo)) +// +// multierr provides a few Invoker implementations out of the box for +// convenience. See [Invoker] for more information. +func AppendInvoke(into *error, invoker Invoker) { + AppendInto(into, invoker.Invoke()) +} + +// AppendFunc is a shorthand for [AppendInvoke]. +// It allows using function or method value directly +// without having to wrap it into an [Invoker] interface. +// +// func doSomething(...) (err error) { +// w, err := startWorker(...) +// if err != nil { +// return err +// } +// +// // multierr will call w.Stop() when this function returns and +// // if the operation fails, it appends its error into the +// // returned error. +// defer multierr.AppendFunc(&err, w.Stop) +// } +func AppendFunc(into *error, fn func() error) { + AppendInvoke(into, Invoke(fn)) +} diff --git a/vendor/go.uber.org/atomic/value.go b/vendor/go.uber.org/multierr/error_post_go120.go similarity index 65% rename from vendor/go.uber.org/atomic/value.go rename to vendor/go.uber.org/multierr/error_post_go120.go index 671f3a38247..a173f9c2515 100644 --- a/vendor/go.uber.org/atomic/value.go +++ b/vendor/go.uber.org/multierr/error_post_go120.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Uber Technologies, Inc. +// Copyright (c) 2017-2023 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,14 +18,31 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package atomic +//go:build go1.20 +// +build go1.20 -import "sync/atomic" +package multierr -// Value shadows the type of the same name from sync/atomic -// https://godoc.org/sync/atomic#Value -type Value struct { - atomic.Value +// Unwrap returns a list of errors wrapped by this multierr. +func (merr *multiError) Unwrap() []error { + return merr.Errors() +} + +type multipleErrors interface { + Unwrap() []error +} + +func extractErrors(err error) []error { + if err == nil { + return nil + } + + // check if the given err is an Unwrapable error that + // implements multipleErrors interface. + eg, ok := err.(multipleErrors) + if !ok { + return []error{err} + } - _ nocmp // disallow non-atomic comparison + return append(([]error)(nil), eg.Unwrap()...) } diff --git a/vendor/go.uber.org/multierr/go113.go b/vendor/go.uber.org/multierr/error_pre_go120.go similarity index 66% rename from vendor/go.uber.org/multierr/go113.go rename to vendor/go.uber.org/multierr/error_pre_go120.go index 264b0eac0dd..93872a3fcd1 100644 --- a/vendor/go.uber.org/multierr/go113.go +++ b/vendor/go.uber.org/multierr/error_pre_go120.go @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2017-2023 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,12 +18,19 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -// +build go1.13 +//go:build !go1.20 +// +build !go1.20 package multierr import "errors" +// Versions of Go before 1.20 did not support the Unwrap() []error method. +// This provides a similar behavior by implementing the Is(..) and As(..) +// methods. +// See the errors.Join proposal for details: +// https://github.com/golang/go/issues/53435 + // As attempts to find the first error in the error list that matches the type // of the value that target points to. // @@ -50,3 +57,23 @@ func (merr *multiError) Is(target error) bool { } return false } + +func extractErrors(err error) []error { + if err == nil { + return nil + } + + // Note that we're casting to multiError, not errorGroup. Our contract is + // that returned errors MAY implement errorGroup. Errors, however, only + // has special behavior for multierr-specific error objects. + // + // This behavior can be expanded in the future but I think it's prudent to + // start with as little as possible in terms of contract and possibility + // of misuse. + eg, ok := err.(*multiError) + if !ok { + return []error{err} + } + + return append(([]error)(nil), eg.Errors()...) +} diff --git a/vendor/go.uber.org/multierr/glide.yaml b/vendor/go.uber.org/multierr/glide.yaml deleted file mode 100644 index 6ef084ec242..00000000000 --- a/vendor/go.uber.org/multierr/glide.yaml +++ /dev/null @@ -1,8 +0,0 @@ -package: go.uber.org/multierr -import: -- package: go.uber.org/atomic - version: ^1 -testImport: -- package: github.com/stretchr/testify - subpackages: - - assert diff --git a/vendor/go.uber.org/zap/.golangci.yml b/vendor/go.uber.org/zap/.golangci.yml new file mode 100644 index 00000000000..fbc6df79065 --- /dev/null +++ b/vendor/go.uber.org/zap/.golangci.yml @@ -0,0 +1,77 @@ +output: + # Make output more digestible with quickfix in vim/emacs/etc. + sort-results: true + print-issued-lines: false + +linters: + # We'll track the golangci-lint default linters manually + # instead of letting them change without our control. + disable-all: true + enable: + # golangci-lint defaults: + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - unused + + # Our own extras: + - gofmt + - nolintlint # lints nolint directives + - revive + +linters-settings: + govet: + # These govet checks are disabled by default, but they're useful. + enable: + - niliness + - reflectvaluecompare + - sortslice + - unusedwrite + + errcheck: + exclude-functions: + # These methods can not fail. + # They operate on an in-memory buffer. + - (*go.uber.org/zap/buffer.Buffer).Write + - (*go.uber.org/zap/buffer.Buffer).WriteByte + - (*go.uber.org/zap/buffer.Buffer).WriteString + + - (*go.uber.org/zap/zapio.Writer).Close + - (*go.uber.org/zap/zapio.Writer).Sync + - (*go.uber.org/zap/zapio.Writer).Write + # Write to zapio.Writer cannot fail, + # so io.WriteString on it cannot fail. + - io.WriteString(*go.uber.org/zap/zapio.Writer) + + # Writing a plain string to a fmt.State cannot fail. + - io.WriteString(fmt.State) + +issues: + # Print all issues reported by all linters. + max-issues-per-linter: 0 + max-same-issues: 0 + + # Don't ignore some of the issues that golangci-lint considers okay. + # This includes documenting all exported entities. + exclude-use-default: false + + exclude-rules: + # Don't warn on unused parameters. + # Parameter names are useful; replacing them with '_' is undesirable. + - linters: [revive] + text: 'unused-parameter: parameter \S+ seems to be unused, consider removing or renaming it as _' + + # staticcheck already has smarter checks for empty blocks. + # revive's empty-block linter has false positives. + # For example, as of writing this, the following is not allowed. + # for foo() { } + - linters: [revive] + text: 'empty-block: this block is empty, you can remove it' + + # Ignore logger.Sync() errcheck failures in example_test.go + # since those are intended to be uncomplicated examples. + - linters: [errcheck] + path: example_test.go + text: 'Error return value of `logger.Sync` is not checked' diff --git a/vendor/go.uber.org/zap/.readme.tmpl b/vendor/go.uber.org/zap/.readme.tmpl index 3154a1e64cf..92aa65d660b 100644 --- a/vendor/go.uber.org/zap/.readme.tmpl +++ b/vendor/go.uber.org/zap/.readme.tmpl @@ -96,14 +96,14 @@ Released under the [MIT License](LICENSE.txt). 1 In particular, keep in mind that we may be benchmarking against slightly older versions of other packages. Versions are -pinned in zap's [glide.lock][] file. [↩](#anchor-versions) +pinned in the [benchmarks/go.mod][] file. [↩](#anchor-versions) -[doc-img]: https://godoc.org/go.uber.org/zap?status.svg -[doc]: https://godoc.org/go.uber.org/zap -[ci-img]: https://travis-ci.com/uber-go/zap.svg?branch=master -[ci]: https://travis-ci.com/uber-go/zap +[doc-img]: https://pkg.go.dev/badge/go.uber.org/zap +[doc]: https://pkg.go.dev/go.uber.org/zap +[ci-img]: https://github.com/uber-go/zap/actions/workflows/go.yml/badge.svg +[ci]: https://github.com/uber-go/zap/actions/workflows/go.yml [cov-img]: https://codecov.io/gh/uber-go/zap/branch/master/graph/badge.svg [cov]: https://codecov.io/gh/uber-go/zap [benchmarking suite]: https://github.com/uber-go/zap/tree/master/benchmarks -[glide.lock]: https://github.com/uber-go/zap/blob/master/glide.lock +[benchmarks/go.mod]: https://github.com/uber-go/zap/blob/master/benchmarks/go.mod diff --git a/vendor/go.uber.org/zap/CHANGELOG.md b/vendor/go.uber.org/zap/CHANGELOG.md index fdfef8808ab..11b46597612 100644 --- a/vendor/go.uber.org/zap/CHANGELOG.md +++ b/vendor/go.uber.org/zap/CHANGELOG.md @@ -1,4 +1,148 @@ # Changelog +All notable changes to this project will be documented in this file. + +This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 1.26.0 (14 Sep 2023) +Enhancements: +* [#1319][]: Add `WithLazy` method to `Logger` which lazily evaluates the structured +context. +* [#1350][]: String encoding is much (~50%) faster now. + +Thanks to @jquirke, @cdvr1993 for their contributions to this release. + +[#1319]: https://github.com/uber-go/zap/pull/1319 +[#1350]: https://github.com/uber-go/zap/pull/1350 + +## 1.25.0 (1 Aug 2023) + +This release contains several improvements including performance, API additions, +and two new experimental packages whose APIs are unstable and may change in the +future. + +Enhancements: +* [#1246][]: Add `zap/exp/zapslog` package for integration with slog. +* [#1273][]: Add `Name` to `Logger` which returns the Logger's name if one is set. +* [#1281][]: Add `zap/exp/expfield` package which contains helper methods +`Str` and `Strs` for constructing String-like zap.Fields. +* [#1310][]: Reduce stack size on `Any`. + +Thanks to @knight42, @dzakaammar, @bcspragu, and @rexywork for their contributions +to this release. + +[#1246]: https://github.com/uber-go/zap/pull/1246 +[#1273]: https://github.com/uber-go/zap/pull/1273 +[#1281]: https://github.com/uber-go/zap/pull/1281 +[#1310]: https://github.com/uber-go/zap/pull/1310 + +## 1.24.0 (30 Nov 2022) + +Enhancements: +* [#1148][]: Add `Level` to both `Logger` and `SugaredLogger` that reports the + current minimum enabled log level. +* [#1185][]: `SugaredLogger` turns errors to zap.Error automatically. + +Thanks to @Abirdcfly, @craigpastro, @nnnkkk7, and @sashamelentyev for their +contributions to this release. + +[#1148]: https://github.coml/uber-go/zap/pull/1148 +[#1185]: https://github.coml/uber-go/zap/pull/1185 + +## 1.23.0 (24 Aug 2022) + +Enhancements: +* [#1147][]: Add a `zapcore.LevelOf` function to determine the level of a + `LevelEnabler` or `Core`. +* [#1155][]: Add `zap.Stringers` field constructor to log arrays of objects + that implement `String() string`. + +[#1147]: https://github.com/uber-go/zap/pull/1147 +[#1155]: https://github.com/uber-go/zap/pull/1155 + +## 1.22.0 (8 Aug 2022) + +Enhancements: +* [#1071][]: Add `zap.Objects` and `zap.ObjectValues` field constructors to log + arrays of objects. With these two constructors, you don't need to implement + `zapcore.ArrayMarshaler` for use with `zap.Array` if those objects implement + `zapcore.ObjectMarshaler`. +* [#1079][]: Add `SugaredLogger.WithOptions` to build a copy of an existing + `SugaredLogger` with the provided options applied. +* [#1080][]: Add `*ln` variants to `SugaredLogger` for each log level. + These functions provide a string joining behavior similar to `fmt.Println`. +* [#1088][]: Add `zap.WithFatalHook` option to control the behavior of the + logger for `Fatal`-level log entries. This defaults to exiting the program. +* [#1108][]: Add a `zap.Must` function that you can use with `NewProduction` or + `NewDevelopment` to panic if the system was unable to build the logger. +* [#1118][]: Add a `Logger.Log` method that allows specifying the log level for + a statement dynamically. + +Thanks to @cardil, @craigpastro, @sashamelentyev, @shota3506, and @zhupeijun +for their contributions to this release. + +[#1071]: https://github.com/uber-go/zap/pull/1071 +[#1079]: https://github.com/uber-go/zap/pull/1079 +[#1080]: https://github.com/uber-go/zap/pull/1080 +[#1088]: https://github.com/uber-go/zap/pull/1088 +[#1108]: https://github.com/uber-go/zap/pull/1108 +[#1118]: https://github.com/uber-go/zap/pull/1118 + +## 1.21.0 (7 Feb 2022) + +Enhancements: +* [#1047][]: Add `zapcore.ParseLevel` to parse a `Level` from a string. +* [#1048][]: Add `zap.ParseAtomicLevel` to parse an `AtomicLevel` from a + string. + +Bugfixes: +* [#1058][]: Fix panic in JSON encoder when `EncodeLevel` is unset. + +Other changes: +* [#1052][]: Improve encoding performance when the `AddCaller` and + `AddStacktrace` options are used together. + +[#1047]: https://github.com/uber-go/zap/pull/1047 +[#1048]: https://github.com/uber-go/zap/pull/1048 +[#1052]: https://github.com/uber-go/zap/pull/1052 +[#1058]: https://github.com/uber-go/zap/pull/1058 + +Thanks to @aerosol and @Techassi for their contributions to this release. + +## 1.20.0 (4 Jan 2022) + +Enhancements: +* [#989][]: Add `EncoderConfig.SkipLineEnding` flag to disable adding newline + characters between log statements. +* [#1039][]: Add `EncoderConfig.NewReflectedEncoder` field to customize JSON + encoding of reflected log fields. + +Bugfixes: +* [#1011][]: Fix inaccurate precision when encoding complex64 as JSON. +* [#554][], [#1017][]: Close JSON namespaces opened in `MarshalLogObject` + methods when the methods return. +* [#1033][]: Avoid panicking in Sampler core if `thereafter` is zero. + +Other changes: +* [#1028][]: Drop support for Go < 1.15. + +[#554]: https://github.com/uber-go/zap/pull/554 +[#989]: https://github.com/uber-go/zap/pull/989 +[#1011]: https://github.com/uber-go/zap/pull/1011 +[#1017]: https://github.com/uber-go/zap/pull/1017 +[#1028]: https://github.com/uber-go/zap/pull/1028 +[#1033]: https://github.com/uber-go/zap/pull/1033 +[#1039]: https://github.com/uber-go/zap/pull/1039 + +Thanks to @psrajat, @lruggieri, @sammyrnycreal for their contributions to this release. + +## 1.19.1 (8 Sep 2021) + +Bugfixes: +* [#1001][]: JSON: Fix complex number encoding with negative imaginary part. Thanks to @hemantjadon. +* [#1003][]: JSON: Fix inaccurate precision when encoding float32. + +[#1001]: https://github.com/uber-go/zap/pull/1001 +[#1003]: https://github.com/uber-go/zap/pull/1003 ## 1.19.0 (9 Aug 2021) @@ -63,6 +207,16 @@ Enhancements: Thanks to @ash2k, @FMLS, @jimmystewpot, @Oncilla, @tsoslow, @tylitianrui, @withshubh, and @wziww for their contributions to this release. +[#865]: https://github.com/uber-go/zap/pull/865 +[#867]: https://github.com/uber-go/zap/pull/867 +[#881]: https://github.com/uber-go/zap/pull/881 +[#903]: https://github.com/uber-go/zap/pull/903 +[#912]: https://github.com/uber-go/zap/pull/912 +[#913]: https://github.com/uber-go/zap/pull/913 +[#928]: https://github.com/uber-go/zap/pull/928 +[#931]: https://github.com/uber-go/zap/pull/931 +[#936]: https://github.com/uber-go/zap/pull/936 + ## 1.16.0 (1 Sep 2020) Bugfixes: @@ -84,6 +238,17 @@ Enhancements: Thanks to @SteelPhase, @tmshn, @lixingwang, @wyxloading, @moul, @segevfiner, @andy-retailnext and @jcorbin for their contributions to this release. +[#629]: https://github.com/uber-go/zap/pull/629 +[#697]: https://github.com/uber-go/zap/pull/697 +[#828]: https://github.com/uber-go/zap/pull/828 +[#835]: https://github.com/uber-go/zap/pull/835 +[#843]: https://github.com/uber-go/zap/pull/843 +[#844]: https://github.com/uber-go/zap/pull/844 +[#852]: https://github.com/uber-go/zap/pull/852 +[#854]: https://github.com/uber-go/zap/pull/854 +[#861]: https://github.com/uber-go/zap/pull/861 +[#862]: https://github.com/uber-go/zap/pull/862 + ## 1.15.0 (23 Apr 2020) Bugfixes: @@ -100,6 +265,11 @@ Enhancements: Thanks to @danielbprice for their contributions to this release. +[#804]: https://github.com/uber-go/zap/pull/804 +[#812]: https://github.com/uber-go/zap/pull/812 +[#806]: https://github.com/uber-go/zap/pull/806 +[#813]: https://github.com/uber-go/zap/pull/813 + ## 1.14.1 (14 Mar 2020) Bugfixes: @@ -112,6 +282,10 @@ Bugfixes: Thanks to @YashishDua for their contributions to this release. +[#791]: https://github.com/uber-go/zap/pull/791 +[#795]: https://github.com/uber-go/zap/pull/795 +[#799]: https://github.com/uber-go/zap/pull/799 + ## 1.14.0 (20 Feb 2020) Enhancements: @@ -122,6 +296,11 @@ Enhancements: Thanks to @caibirdme for their contributions to this release. +[#771]: https://github.com/uber-go/zap/pull/771 +[#773]: https://github.com/uber-go/zap/pull/773 +[#775]: https://github.com/uber-go/zap/pull/775 +[#786]: https://github.com/uber-go/zap/pull/786 + ## 1.13.0 (13 Nov 2019) Enhancements: @@ -130,11 +309,15 @@ Enhancements: Thanks to @jbizzle for their contributions to this release. +[#758]: https://github.com/uber-go/zap/pull/758 + ## 1.12.0 (29 Oct 2019) Enhancements: * [#751][]: Migrate to Go modules. +[#751]: https://github.com/uber-go/zap/pull/751 + ## 1.11.0 (21 Oct 2019) Enhancements: @@ -143,6 +326,9 @@ Enhancements: Thanks to @juicemia, @uhthomas for their contributions to this release. +[#725]: https://github.com/uber-go/zap/pull/725 +[#736]: https://github.com/uber-go/zap/pull/736 + ## 1.10.0 (29 Apr 2019) Bugfixes: @@ -160,12 +346,20 @@ Enhancements: Thanks to @iaroslav-ciupin, @lelenanam, @joa, @NWilson for their contributions to this release. +[#657]: https://github.com/uber-go/zap/pull/657 +[#706]: https://github.com/uber-go/zap/pull/706 +[#610]: https://github.com/uber-go/zap/pull/610 +[#675]: https://github.com/uber-go/zap/pull/675 +[#704]: https://github.com/uber-go/zap/pull/704 + ## v1.9.1 (06 Aug 2018) Bugfixes: * [#614][]: MapObjectEncoder should not ignore empty slices. +[#614]: https://github.com/uber-go/zap/pull/614 + ## v1.9.0 (19 Jul 2018) Enhancements: @@ -175,6 +369,10 @@ Enhancements: Thanks to @nfarah86, @AlekSi, @JeanMertz, @philippgille, @etsangsplk, and @dimroc for their contributions to this release. +[#602]: https://github.com/uber-go/zap/pull/602 +[#572]: https://github.com/uber-go/zap/pull/572 +[#606]: https://github.com/uber-go/zap/pull/606 + ## v1.8.0 (13 Apr 2018) Enhancements: @@ -188,11 +386,18 @@ Bugfixes: Thanks to @DiSiqueira and @djui for their contributions to this release. +[#508]: https://github.com/uber-go/zap/pull/508 +[#518]: https://github.com/uber-go/zap/pull/518 +[#577]: https://github.com/uber-go/zap/pull/577 +[#574]: https://github.com/uber-go/zap/pull/574 + ## v1.7.1 (25 Sep 2017) Bugfixes: * [#504][]: Store strings when using AddByteString with the map encoder. +[#504]: https://github.com/uber-go/zap/pull/504 + ## v1.7.0 (21 Sep 2017) Enhancements: @@ -200,6 +405,8 @@ Enhancements: * [#487][]: Add `NewStdLogAt`, which extends `NewStdLog` by allowing the user to specify the level of the logged messages. +[#487]: https://github.com/uber-go/zap/pull/487 + ## v1.6.0 (30 Aug 2017) Enhancements: @@ -208,6 +415,9 @@ Enhancements: * [#490][]: Add a `ContextMap` method to observer logs for simpler field validation in tests. +[#490]: https://github.com/uber-go/zap/pull/490 +[#491]: https://github.com/uber-go/zap/pull/491 + ## v1.5.0 (22 Jul 2017) Enhancements: @@ -221,6 +431,11 @@ Bugfixes: Thanks to @richard-tunein and @pavius for their contributions to this release. +[#477]: https://github.com/uber-go/zap/pull/477 +[#465]: https://github.com/uber-go/zap/pull/465 +[#460]: https://github.com/uber-go/zap/pull/460 +[#470]: https://github.com/uber-go/zap/pull/470 + ## v1.4.1 (08 Jun 2017) This release fixes two bugs. @@ -230,6 +445,9 @@ Bugfixes: * [#435][]: Support a variety of case conventions when unmarshaling levels. * [#444][]: Fix a panic in the observer. +[#435]: https://github.com/uber-go/zap/pull/435 +[#444]: https://github.com/uber-go/zap/pull/444 + ## v1.4.0 (12 May 2017) This release adds a few small features and is fully backward-compatible. @@ -242,6 +460,10 @@ Enhancements: * [#431][]: Make `zap.AtomicLevel` implement `fmt.Stringer`, which makes a variety of operations a bit simpler. +[#424]: https://github.com/uber-go/zap/pull/424 +[#425]: https://github.com/uber-go/zap/pull/425 +[#431]: https://github.com/uber-go/zap/pull/431 + ## v1.3.0 (25 Apr 2017) This release adds an enhancement to zap's testing helpers as well as the @@ -253,6 +475,9 @@ Enhancements: particularly useful when testing the `SugaredLogger`. * [#416][]: Make `AtomicLevel` implement `encoding.TextMarshaler`. +[#415]: https://github.com/uber-go/zap/pull/415 +[#416]: https://github.com/uber-go/zap/pull/416 + ## v1.2.0 (13 Apr 2017) This release adds a gRPC compatibility wrapper. It is fully backward-compatible. @@ -262,6 +487,8 @@ Enhancements: * [#402][]: Add a `zapgrpc` package that wraps zap's Logger and implements `grpclog.Logger`. +[#402]: https://github.com/uber-go/zap/pull/402 + ## v1.1.0 (31 Mar 2017) This release fixes two bugs and adds some enhancements to zap's testing helpers. @@ -279,6 +506,10 @@ Enhancements: Thanks to @moitias for contributing to this release. +[#385]: https://github.com/uber-go/zap/pull/385 +[#396]: https://github.com/uber-go/zap/pull/396 +[#386]: https://github.com/uber-go/zap/pull/386 + ## v1.0.0 (14 Mar 2017) This is zap's first stable release. All exported APIs are now final, and no @@ -324,6 +555,20 @@ Enhancements: Thanks to @suyash, @htrendev, @flisky, @Ulexus, and @skipor for their contributions to this release. +[#366]: https://github.com/uber-go/zap/pull/366 +[#364]: https://github.com/uber-go/zap/pull/364 +[#371]: https://github.com/uber-go/zap/pull/371 +[#362]: https://github.com/uber-go/zap/pull/362 +[#369]: https://github.com/uber-go/zap/pull/369 +[#347]: https://github.com/uber-go/zap/pull/347 +[#373]: https://github.com/uber-go/zap/pull/373 +[#348]: https://github.com/uber-go/zap/pull/348 +[#327]: https://github.com/uber-go/zap/pull/327 +[#376]: https://github.com/uber-go/zap/pull/376 +[#346]: https://github.com/uber-go/zap/pull/346 +[#365]: https://github.com/uber-go/zap/pull/365 +[#372]: https://github.com/uber-go/zap/pull/372 + ## v1.0.0-rc.3 (7 Mar 2017) This is the third release candidate for zap's stable release. There are no @@ -345,6 +590,11 @@ Enhancements: Thanks to @ansel1 and @suyash for their contributions to this release. +[#339]: https://github.com/uber-go/zap/pull/339 +[#307]: https://github.com/uber-go/zap/pull/307 +[#353]: https://github.com/uber-go/zap/pull/353 +[#311]: https://github.com/uber-go/zap/pull/311 + ## v1.0.0-rc.2 (21 Feb 2017) This is the second release candidate for zap's stable release. It includes two @@ -382,6 +632,15 @@ Enhancements: Thanks to @skipor and @chapsuk for their contributions to this release. +[#316]: https://github.com/uber-go/zap/pull/316 +[#309]: https://github.com/uber-go/zap/pull/309 +[#317]: https://github.com/uber-go/zap/pull/317 +[#321]: https://github.com/uber-go/zap/pull/321 +[#325]: https://github.com/uber-go/zap/pull/325 +[#333]: https://github.com/uber-go/zap/pull/333 +[#326]: https://github.com/uber-go/zap/pull/326 +[#300]: https://github.com/uber-go/zap/pull/300 + ## v1.0.0-rc.1 (14 Feb 2017) This is the first release candidate for zap's stable release. There are multiple @@ -410,95 +669,3 @@ backward compatibility concerns and all functionality is new. Early zap adopters should pin to the 0.1.x minor version until they're ready to upgrade to the upcoming stable release. - -[#316]: https://github.com/uber-go/zap/pull/316 -[#309]: https://github.com/uber-go/zap/pull/309 -[#317]: https://github.com/uber-go/zap/pull/317 -[#321]: https://github.com/uber-go/zap/pull/321 -[#325]: https://github.com/uber-go/zap/pull/325 -[#333]: https://github.com/uber-go/zap/pull/333 -[#326]: https://github.com/uber-go/zap/pull/326 -[#300]: https://github.com/uber-go/zap/pull/300 -[#339]: https://github.com/uber-go/zap/pull/339 -[#307]: https://github.com/uber-go/zap/pull/307 -[#353]: https://github.com/uber-go/zap/pull/353 -[#311]: https://github.com/uber-go/zap/pull/311 -[#366]: https://github.com/uber-go/zap/pull/366 -[#364]: https://github.com/uber-go/zap/pull/364 -[#371]: https://github.com/uber-go/zap/pull/371 -[#362]: https://github.com/uber-go/zap/pull/362 -[#369]: https://github.com/uber-go/zap/pull/369 -[#347]: https://github.com/uber-go/zap/pull/347 -[#373]: https://github.com/uber-go/zap/pull/373 -[#348]: https://github.com/uber-go/zap/pull/348 -[#327]: https://github.com/uber-go/zap/pull/327 -[#376]: https://github.com/uber-go/zap/pull/376 -[#346]: https://github.com/uber-go/zap/pull/346 -[#365]: https://github.com/uber-go/zap/pull/365 -[#372]: https://github.com/uber-go/zap/pull/372 -[#385]: https://github.com/uber-go/zap/pull/385 -[#396]: https://github.com/uber-go/zap/pull/396 -[#386]: https://github.com/uber-go/zap/pull/386 -[#402]: https://github.com/uber-go/zap/pull/402 -[#415]: https://github.com/uber-go/zap/pull/415 -[#416]: https://github.com/uber-go/zap/pull/416 -[#424]: https://github.com/uber-go/zap/pull/424 -[#425]: https://github.com/uber-go/zap/pull/425 -[#431]: https://github.com/uber-go/zap/pull/431 -[#435]: https://github.com/uber-go/zap/pull/435 -[#444]: https://github.com/uber-go/zap/pull/444 -[#477]: https://github.com/uber-go/zap/pull/477 -[#465]: https://github.com/uber-go/zap/pull/465 -[#460]: https://github.com/uber-go/zap/pull/460 -[#470]: https://github.com/uber-go/zap/pull/470 -[#487]: https://github.com/uber-go/zap/pull/487 -[#490]: https://github.com/uber-go/zap/pull/490 -[#491]: https://github.com/uber-go/zap/pull/491 -[#504]: https://github.com/uber-go/zap/pull/504 -[#508]: https://github.com/uber-go/zap/pull/508 -[#518]: https://github.com/uber-go/zap/pull/518 -[#577]: https://github.com/uber-go/zap/pull/577 -[#574]: https://github.com/uber-go/zap/pull/574 -[#602]: https://github.com/uber-go/zap/pull/602 -[#572]: https://github.com/uber-go/zap/pull/572 -[#606]: https://github.com/uber-go/zap/pull/606 -[#614]: https://github.com/uber-go/zap/pull/614 -[#657]: https://github.com/uber-go/zap/pull/657 -[#706]: https://github.com/uber-go/zap/pull/706 -[#610]: https://github.com/uber-go/zap/pull/610 -[#675]: https://github.com/uber-go/zap/pull/675 -[#704]: https://github.com/uber-go/zap/pull/704 -[#725]: https://github.com/uber-go/zap/pull/725 -[#736]: https://github.com/uber-go/zap/pull/736 -[#751]: https://github.com/uber-go/zap/pull/751 -[#758]: https://github.com/uber-go/zap/pull/758 -[#771]: https://github.com/uber-go/zap/pull/771 -[#773]: https://github.com/uber-go/zap/pull/773 -[#775]: https://github.com/uber-go/zap/pull/775 -[#786]: https://github.com/uber-go/zap/pull/786 -[#791]: https://github.com/uber-go/zap/pull/791 -[#795]: https://github.com/uber-go/zap/pull/795 -[#799]: https://github.com/uber-go/zap/pull/799 -[#804]: https://github.com/uber-go/zap/pull/804 -[#812]: https://github.com/uber-go/zap/pull/812 -[#806]: https://github.com/uber-go/zap/pull/806 -[#813]: https://github.com/uber-go/zap/pull/813 -[#629]: https://github.com/uber-go/zap/pull/629 -[#697]: https://github.com/uber-go/zap/pull/697 -[#828]: https://github.com/uber-go/zap/pull/828 -[#835]: https://github.com/uber-go/zap/pull/835 -[#843]: https://github.com/uber-go/zap/pull/843 -[#844]: https://github.com/uber-go/zap/pull/844 -[#852]: https://github.com/uber-go/zap/pull/852 -[#854]: https://github.com/uber-go/zap/pull/854 -[#861]: https://github.com/uber-go/zap/pull/861 -[#862]: https://github.com/uber-go/zap/pull/862 -[#865]: https://github.com/uber-go/zap/pull/865 -[#867]: https://github.com/uber-go/zap/pull/867 -[#881]: https://github.com/uber-go/zap/pull/881 -[#903]: https://github.com/uber-go/zap/pull/903 -[#912]: https://github.com/uber-go/zap/pull/912 -[#913]: https://github.com/uber-go/zap/pull/913 -[#928]: https://github.com/uber-go/zap/pull/928 -[#931]: https://github.com/uber-go/zap/pull/931 -[#936]: https://github.com/uber-go/zap/pull/936 diff --git a/vendor/go.uber.org/zap/CONTRIBUTING.md b/vendor/go.uber.org/zap/CONTRIBUTING.md index 5cd96568713..ea02f3cae2d 100644 --- a/vendor/go.uber.org/zap/CONTRIBUTING.md +++ b/vendor/go.uber.org/zap/CONTRIBUTING.md @@ -16,7 +16,7 @@ you to accept the CLA when you open your pull request. [Fork][fork], then clone the repository: -``` +```bash mkdir -p $GOPATH/src/go.uber.org cd $GOPATH/src/go.uber.org git clone git@github.com:your_github_username/zap.git @@ -27,21 +27,16 @@ git fetch upstream Make sure that the tests and the linters pass: -``` +```bash make test make lint ``` -If you're not using the minor version of Go specified in the Makefile's -`LINTABLE_MINOR_VERSIONS` variable, `make lint` doesn't do anything. This is -fine, but it means that you'll only discover lint failures after you open your -pull request. - ## Making Changes Start by creating a new branch for your changes: -``` +```bash cd $GOPATH/src/go.uber.org/zap git checkout master git fetch upstream @@ -52,22 +47,22 @@ git checkout -b cool_new_feature Make your changes, then ensure that `make lint` and `make test` still pass. If you're satisfied with your changes, push them to your fork. -``` +```bash git push origin cool_new_feature ``` Then use the GitHub UI to open a pull request. -At this point, you're waiting on us to review your changes. We *try* to respond +At this point, you're waiting on us to review your changes. We _try_ to respond to issues and pull requests within a few business days, and we may suggest some improvements or alternatives. Once your changes are approved, one of the project maintainers will merge them. We're much more likely to approve your changes if you: -* Add tests for new functionality. -* Write a [good commit message][commit-message]. -* Maintain backward compatibility. +- Add tests for new functionality. +- Write a [good commit message][commit-message]. +- Maintain backward compatibility. [fork]: https://github.com/uber-go/zap/fork [open-issue]: https://github.com/uber-go/zap/issues/new diff --git a/vendor/go.uber.org/zap/Makefile b/vendor/go.uber.org/zap/Makefile index 9b1bc3b0e1d..eb1cee53bd5 100644 --- a/vendor/go.uber.org/zap/Makefile +++ b/vendor/go.uber.org/zap/Makefile @@ -1,50 +1,51 @@ -export GOBIN ?= $(shell pwd)/bin +# Directory containing the Makefile. +PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) -GOLINT = $(GOBIN)/golint -STATICCHECK = $(GOBIN)/staticcheck +export GOBIN ?= $(PROJECT_ROOT)/bin +export PATH := $(GOBIN):$(PATH) + +GOVULNCHECK = $(GOBIN)/govulncheck BENCH_FLAGS ?= -cpuprofile=cpu.pprof -memprofile=mem.pprof -benchmem # Directories containing independent Go modules. -# -# We track coverage only for the main module. -MODULE_DIRS = . ./benchmarks ./zapgrpc/internal/test +MODULE_DIRS = . ./exp ./benchmarks ./zapgrpc/internal/test -# Many Go tools take file globs or directories as arguments instead of packages. -GO_FILES := $(shell \ - find . '(' -path '*/.*' -o -path './vendor' ')' -prune \ - -o -name '*.go' -print | cut -b3-) +# Directories that we want to track coverage for. +COVER_DIRS = . ./exp .PHONY: all all: lint test .PHONY: lint -lint: $(GOLINT) $(STATICCHECK) - @rm -rf lint.log - @echo "Checking formatting..." - @gofmt -d -s $(GO_FILES) 2>&1 | tee lint.log - @echo "Checking vet..." - @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go vet ./... 2>&1) &&) true | tee -a lint.log - @echo "Checking lint..." - @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(GOLINT) ./... 2>&1) &&) true | tee -a lint.log - @echo "Checking staticcheck..." - @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && $(STATICCHECK) ./... 2>&1) &&) true | tee -a lint.log - @echo "Checking for unresolved FIXMEs..." - @git grep -i fixme | grep -v -e Makefile | tee -a lint.log - @echo "Checking for license headers..." - @./checklicense.sh | tee -a lint.log - @[ ! -s lint.log ] - @echo "Checking 'go mod tidy'..." - @make tidy - @if ! git diff --quiet; then \ - echo "'go mod tidy' resulted in changes or working tree is dirty:"; \ - git --no-pager diff; \ - fi - -$(GOLINT): - cd tools && go install golang.org/x/lint/golint - -$(STATICCHECK): - cd tools && go install honnef.co/go/tools/cmd/staticcheck +lint: golangci-lint tidy-lint license-lint + +.PHONY: golangci-lint +golangci-lint: + @$(foreach mod,$(MODULE_DIRS), \ + (cd $(mod) && \ + echo "[lint] golangci-lint: $(mod)" && \ + golangci-lint run --path-prefix $(mod)) &&) true + +.PHONY: tidy +tidy: + @$(foreach dir,$(MODULE_DIRS), \ + (cd $(dir) && go mod tidy) &&) true + +.PHONY: tidy-lint +tidy-lint: + @$(foreach mod,$(MODULE_DIRS), \ + (cd $(mod) && \ + echo "[lint] tidy: $(mod)" && \ + go mod tidy && \ + git diff --exit-code -- go.mod go.sum) &&) true + + +.PHONY: license-lint +license-lint: + ./checklicense.sh + +$(GOVULNCHECK): + cd tools && go install golang.org/x/vuln/cmd/govulncheck .PHONY: test test: @@ -52,8 +53,10 @@ test: .PHONY: cover cover: - go test -race -coverprofile=cover.out -coverpkg=./... ./... - go tool cover -html=cover.out -o cover.html + @$(foreach dir,$(COVER_DIRS), ( \ + cd $(dir) && \ + go test -race -coverprofile=cover.out -coverpkg=./... ./... \ + && go tool cover -html=cover.out -o cover.html) &&) true .PHONY: bench BENCH ?= . @@ -68,6 +71,6 @@ updatereadme: rm -f README.md cat .readme.tmpl | go run internal/readme/readme.go > README.md -.PHONY: tidy -tidy: - @$(foreach dir,$(MODULE_DIRS),(cd $(dir) && go mod tidy) &&) true +.PHONY: vulncheck +vulncheck: $(GOVULNCHECK) + $(GOVULNCHECK) ./... diff --git a/vendor/go.uber.org/zap/README.md b/vendor/go.uber.org/zap/README.md index 1e64d6cffc1..9de08927be9 100644 --- a/vendor/go.uber.org/zap/README.md +++ b/vendor/go.uber.org/zap/README.md @@ -66,38 +66,41 @@ Log a message and 10 fields: | Package | Time | Time % to zap | Objects Allocated | | :------ | :--: | :-----------: | :---------------: | -| :zap: zap | 862 ns/op | +0% | 5 allocs/op -| :zap: zap (sugared) | 1250 ns/op | +45% | 11 allocs/op -| zerolog | 4021 ns/op | +366% | 76 allocs/op -| go-kit | 4542 ns/op | +427% | 105 allocs/op -| apex/log | 26785 ns/op | +3007% | 115 allocs/op -| logrus | 29501 ns/op | +3322% | 125 allocs/op -| log15 | 29906 ns/op | +3369% | 122 allocs/op +| :zap: zap | 1744 ns/op | +0% | 5 allocs/op +| :zap: zap (sugared) | 2483 ns/op | +42% | 10 allocs/op +| zerolog | 918 ns/op | -47% | 1 allocs/op +| go-kit | 5590 ns/op | +221% | 57 allocs/op +| slog | 5640 ns/op | +223% | 40 allocs/op +| apex/log | 21184 ns/op | +1115% | 63 allocs/op +| logrus | 24338 ns/op | +1296% | 79 allocs/op +| log15 | 26054 ns/op | +1394% | 74 allocs/op Log a message with a logger that already has 10 fields of context: | Package | Time | Time % to zap | Objects Allocated | | :------ | :--: | :-----------: | :---------------: | -| :zap: zap | 126 ns/op | +0% | 0 allocs/op -| :zap: zap (sugared) | 187 ns/op | +48% | 2 allocs/op -| zerolog | 88 ns/op | -30% | 0 allocs/op -| go-kit | 5087 ns/op | +3937% | 103 allocs/op -| log15 | 18548 ns/op | +14621% | 73 allocs/op -| apex/log | 26012 ns/op | +20544% | 104 allocs/op -| logrus | 27236 ns/op | +21516% | 113 allocs/op +| :zap: zap | 193 ns/op | +0% | 0 allocs/op +| :zap: zap (sugared) | 227 ns/op | +18% | 1 allocs/op +| zerolog | 81 ns/op | -58% | 0 allocs/op +| slog | 322 ns/op | +67% | 0 allocs/op +| go-kit | 5377 ns/op | +2686% | 56 allocs/op +| apex/log | 19518 ns/op | +10013% | 53 allocs/op +| log15 | 19812 ns/op | +10165% | 70 allocs/op +| logrus | 21997 ns/op | +11297% | 68 allocs/op Log a static string, without any context or `printf`-style templating: | Package | Time | Time % to zap | Objects Allocated | | :------ | :--: | :-----------: | :---------------: | -| :zap: zap | 118 ns/op | +0% | 0 allocs/op -| :zap: zap (sugared) | 191 ns/op | +62% | 2 allocs/op -| zerolog | 93 ns/op | -21% | 0 allocs/op -| go-kit | 280 ns/op | +137% | 11 allocs/op -| standard library | 499 ns/op | +323% | 2 allocs/op -| apex/log | 1990 ns/op | +1586% | 10 allocs/op -| logrus | 3129 ns/op | +2552% | 24 allocs/op -| log15 | 3887 ns/op | +3194% | 23 allocs/op +| :zap: zap | 165 ns/op | +0% | 0 allocs/op +| :zap: zap (sugared) | 212 ns/op | +28% | 1 allocs/op +| zerolog | 95 ns/op | -42% | 0 allocs/op +| slog | 296 ns/op | +79% | 0 allocs/op +| go-kit | 415 ns/op | +152% | 9 allocs/op +| standard library | 422 ns/op | +156% | 2 allocs/op +| apex/log | 1601 ns/op | +870% | 5 allocs/op +| logrus | 3017 ns/op | +1728% | 23 allocs/op +| log15 | 3469 ns/op | +2002% | 20 allocs/op ## Development Status: Stable diff --git a/vendor/go.uber.org/zap/array.go b/vendor/go.uber.org/zap/array.go index 5be3704a3e1..abfccb566d5 100644 --- a/vendor/go.uber.org/zap/array.go +++ b/vendor/go.uber.org/zap/array.go @@ -21,6 +21,7 @@ package zap import ( + "fmt" "time" "go.uber.org/zap/zapcore" @@ -94,11 +95,137 @@ func Int8s(key string, nums []int8) Field { return Array(key, int8s(nums)) } +// Objects constructs a field with the given key, holding a list of the +// provided objects that can be marshaled by Zap. +// +// Note that these objects must implement zapcore.ObjectMarshaler directly. +// That is, if you're trying to marshal a []Request, the MarshalLogObject +// method must be declared on the Request type, not its pointer (*Request). +// If it's on the pointer, use ObjectValues. +// +// Given an object that implements MarshalLogObject on the value receiver, you +// can log a slice of those objects with Objects like so: +// +// type Author struct{ ... } +// func (a Author) MarshalLogObject(enc zapcore.ObjectEncoder) error +// +// var authors []Author = ... +// logger.Info("loading article", zap.Objects("authors", authors)) +// +// Similarly, given a type that implements MarshalLogObject on its pointer +// receiver, you can log a slice of pointers to that object with Objects like +// so: +// +// type Request struct{ ... } +// func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error +// +// var requests []*Request = ... +// logger.Info("sending requests", zap.Objects("requests", requests)) +// +// If instead, you have a slice of values of such an object, use the +// ObjectValues constructor. +// +// var requests []Request = ... +// logger.Info("sending requests", zap.ObjectValues("requests", requests)) +func Objects[T zapcore.ObjectMarshaler](key string, values []T) Field { + return Array(key, objects[T](values)) +} + +type objects[T zapcore.ObjectMarshaler] []T + +func (os objects[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for _, o := range os { + if err := arr.AppendObject(o); err != nil { + return err + } + } + return nil +} + +// ObjectMarshalerPtr is a constraint that specifies that the given type +// implements zapcore.ObjectMarshaler on a pointer receiver. +type ObjectMarshalerPtr[T any] interface { + *T + zapcore.ObjectMarshaler +} + +// ObjectValues constructs a field with the given key, holding a list of the +// provided objects, where pointers to these objects can be marshaled by Zap. +// +// Note that pointers to these objects must implement zapcore.ObjectMarshaler. +// That is, if you're trying to marshal a []Request, the MarshalLogObject +// method must be declared on the *Request type, not the value (Request). +// If it's on the value, use Objects. +// +// Given an object that implements MarshalLogObject on the pointer receiver, +// you can log a slice of those objects with ObjectValues like so: +// +// type Request struct{ ... } +// func (r *Request) MarshalLogObject(enc zapcore.ObjectEncoder) error +// +// var requests []Request = ... +// logger.Info("sending requests", zap.ObjectValues("requests", requests)) +// +// If instead, you have a slice of pointers of such an object, use the Objects +// field constructor. +// +// var requests []*Request = ... +// logger.Info("sending requests", zap.Objects("requests", requests)) +func ObjectValues[T any, P ObjectMarshalerPtr[T]](key string, values []T) Field { + return Array(key, objectValues[T, P](values)) +} + +type objectValues[T any, P ObjectMarshalerPtr[T]] []T + +func (os objectValues[T, P]) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for i := range os { + // It is necessary for us to explicitly reference the "P" type. + // We cannot simply pass "&os[i]" to AppendObject because its type + // is "*T", which the type system does not consider as + // implementing ObjectMarshaler. + // Only the type "P" satisfies ObjectMarshaler, which we have + // to convert "*T" to explicitly. + var p P = &os[i] + if err := arr.AppendObject(p); err != nil { + return err + } + } + return nil +} + // Strings constructs a field that carries a slice of strings. func Strings(key string, ss []string) Field { return Array(key, stringArray(ss)) } +// Stringers constructs a field with the given key, holding a list of the +// output provided by the value's String method +// +// Given an object that implements String on the value receiver, you +// can log a slice of those objects with Objects like so: +// +// type Request struct{ ... } +// func (a Request) String() string +// +// var requests []Request = ... +// logger.Info("sending requests", zap.Stringers("requests", requests)) +// +// Note that these objects must implement fmt.Stringer directly. +// That is, if you're trying to marshal a []Request, the String method +// must be declared on the Request type, not its pointer (*Request). +func Stringers[T fmt.Stringer](key string, values []T) Field { + return Array(key, stringers[T](values)) +} + +type stringers[T fmt.Stringer] []T + +func (os stringers[T]) MarshalLogArray(arr zapcore.ArrayEncoder) error { + for _, o := range os { + arr.AppendString(o.String()) + } + return nil +} + // Times constructs a field that carries a slice of time.Times. func Times(key string, ts []time.Time) Field { return Array(key, times(ts)) diff --git a/vendor/go.uber.org/zap/buffer/buffer.go b/vendor/go.uber.org/zap/buffer/buffer.go index 9e929cd98e6..27fb5cd5dab 100644 --- a/vendor/go.uber.org/zap/buffer/buffer.go +++ b/vendor/go.uber.org/zap/buffer/buffer.go @@ -42,6 +42,11 @@ func (b *Buffer) AppendByte(v byte) { b.bs = append(b.bs, v) } +// AppendBytes writes a single byte to the Buffer. +func (b *Buffer) AppendBytes(v []byte) { + b.bs = append(b.bs, v...) +} + // AppendString writes a string to the Buffer. func (b *Buffer) AppendString(s string) { b.bs = append(b.bs, s...) diff --git a/vendor/go.uber.org/zap/buffer/pool.go b/vendor/go.uber.org/zap/buffer/pool.go index 8fb3e202cf4..846323360ee 100644 --- a/vendor/go.uber.org/zap/buffer/pool.go +++ b/vendor/go.uber.org/zap/buffer/pool.go @@ -20,25 +20,29 @@ package buffer -import "sync" +import ( + "go.uber.org/zap/internal/pool" +) // A Pool is a type-safe wrapper around a sync.Pool. type Pool struct { - p *sync.Pool + p *pool.Pool[*Buffer] } // NewPool constructs a new Pool. func NewPool() Pool { - return Pool{p: &sync.Pool{ - New: func() interface{} { - return &Buffer{bs: make([]byte, 0, _size)} - }, - }} + return Pool{ + p: pool.New(func() *Buffer { + return &Buffer{ + bs: make([]byte, 0, _size), + } + }), + } } // Get retrieves a Buffer from the pool, creating one if necessary. func (p Pool) Get() *Buffer { - buf := p.p.Get().(*Buffer) + buf := p.p.Get() buf.Reset() buf.pool = p return buf diff --git a/vendor/go.uber.org/zap/config.go b/vendor/go.uber.org/zap/config.go index 55637fb0b4b..e76e4e64fbe 100644 --- a/vendor/go.uber.org/zap/config.go +++ b/vendor/go.uber.org/zap/config.go @@ -21,7 +21,7 @@ package zap import ( - "fmt" + "errors" "sort" "time" @@ -95,6 +95,32 @@ type Config struct { // NewProductionEncoderConfig returns an opinionated EncoderConfig for // production environments. +// +// Messages encoded with this configuration will be JSON-formatted +// and will have the following keys by default: +// +// - "level": The logging level (e.g. "info", "error"). +// - "ts": The current time in number of seconds since the Unix epoch. +// - "msg": The message passed to the log statement. +// - "caller": If available, a short path to the file and line number +// where the log statement was issued. +// The logger configuration determines whether this field is captured. +// - "stacktrace": If available, a stack trace from the line +// where the log statement was issued. +// The logger configuration determines whether this field is captured. +// +// By default, the following formats are used for different types: +// +// - Time is formatted as floating-point number of seconds since the Unix +// epoch. +// - Duration is formatted as floating-point number of seconds. +// +// You may change these by setting the appropriate fields in the returned +// object. +// For example, use the following to change the time encoding format: +// +// cfg := zap.NewProductionEncoderConfig() +// cfg.EncodeTime = zapcore.ISO8601TimeEncoder func NewProductionEncoderConfig() zapcore.EncoderConfig { return zapcore.EncoderConfig{ TimeKey: "ts", @@ -112,11 +138,22 @@ func NewProductionEncoderConfig() zapcore.EncoderConfig { } } -// NewProductionConfig is a reasonable production logging configuration. -// Logging is enabled at InfoLevel and above. +// NewProductionConfig builds a reasonable default production logging +// configuration. +// Logging is enabled at InfoLevel and above, and uses a JSON encoder. +// Logs are written to standard error. +// Stacktraces are included on logs of ErrorLevel and above. +// DPanicLevel logs will not panic, but will write a stacktrace. +// +// Sampling is enabled at 100:100 by default, +// meaning that after the first 100 log entries +// with the same level and message in the same second, +// it will log every 100th entry +// with the same level and message in the same second. +// You may disable this behavior by setting Sampling to nil. // -// It uses a JSON encoder, writes to standard error, and enables sampling. -// Stacktraces are automatically included on logs of ErrorLevel and above. +// See [NewProductionEncoderConfig] for information +// on the default encoder configuration. func NewProductionConfig() Config { return Config{ Level: NewAtomicLevelAt(InfoLevel), @@ -134,6 +171,32 @@ func NewProductionConfig() Config { // NewDevelopmentEncoderConfig returns an opinionated EncoderConfig for // development environments. +// +// Messages encoded with this configuration will use Zap's console encoder +// intended to print human-readable output. +// It will print log messages with the following information: +// +// - The log level (e.g. "INFO", "ERROR"). +// - The time in ISO8601 format (e.g. "2017-01-01T12:00:00Z"). +// - The message passed to the log statement. +// - If available, a short path to the file and line number +// where the log statement was issued. +// The logger configuration determines whether this field is captured. +// - If available, a stacktrace from the line +// where the log statement was issued. +// The logger configuration determines whether this field is captured. +// +// By default, the following formats are used for different types: +// +// - Time is formatted in ISO8601 format (e.g. "2017-01-01T12:00:00Z"). +// - Duration is formatted as a string (e.g. "1.234s"). +// +// You may change these by setting the appropriate fields in the returned +// object. +// For example, use the following to change the time encoding format: +// +// cfg := zap.NewDevelopmentEncoderConfig() +// cfg.EncodeTime = zapcore.ISO8601TimeEncoder func NewDevelopmentEncoderConfig() zapcore.EncoderConfig { return zapcore.EncoderConfig{ // Keys can be anything except the empty string. @@ -152,12 +215,15 @@ func NewDevelopmentEncoderConfig() zapcore.EncoderConfig { } } -// NewDevelopmentConfig is a reasonable development logging configuration. -// Logging is enabled at DebugLevel and above. +// NewDevelopmentConfig builds a reasonable default development logging +// configuration. +// Logging is enabled at DebugLevel and above, and uses a console encoder. +// Logs are written to standard error. +// Stacktraces are included on logs of WarnLevel and above. +// DPanicLevel logs will panic. // -// It enables development mode (which makes DPanicLevel logs panic), uses a -// console encoder, writes to standard error, and disables sampling. -// Stacktraces are automatically included on logs of WarnLevel and above. +// See [NewDevelopmentEncoderConfig] for information +// on the default encoder configuration. func NewDevelopmentConfig() Config { return Config{ Level: NewAtomicLevelAt(DebugLevel), @@ -182,7 +248,7 @@ func (cfg Config) Build(opts ...Option) (*Logger, error) { } if cfg.Level == (AtomicLevel{}) { - return nil, fmt.Errorf("missing Level") + return nil, errors.New("missing Level") } log := New( diff --git a/vendor/go.uber.org/zap/doc.go b/vendor/go.uber.org/zap/doc.go index 8638dd1b965..3c50d7b4d3f 100644 --- a/vendor/go.uber.org/zap/doc.go +++ b/vendor/go.uber.org/zap/doc.go @@ -32,7 +32,7 @@ // they need to count every allocation and when they'd prefer a more familiar, // loosely typed API. // -// Choosing a Logger +// # Choosing a Logger // // In contexts where performance is nice, but not critical, use the // SugaredLogger. It's 4-10x faster than other structured logging packages and @@ -41,14 +41,15 @@ // variadic number of key-value pairs. (For more advanced use cases, they also // accept strongly typed fields - see the SugaredLogger.With documentation for // details.) -// sugar := zap.NewExample().Sugar() -// defer sugar.Sync() -// sugar.Infow("failed to fetch URL", -// "url", "http://example.com", -// "attempt", 3, -// "backoff", time.Second, -// ) -// sugar.Infof("failed to fetch URL: %s", "http://example.com") +// +// sugar := zap.NewExample().Sugar() +// defer sugar.Sync() +// sugar.Infow("failed to fetch URL", +// "url", "http://example.com", +// "attempt", 3, +// "backoff", time.Second, +// ) +// sugar.Infof("failed to fetch URL: %s", "http://example.com") // // By default, loggers are unbuffered. However, since zap's low-level APIs // allow buffering, calling Sync before letting your process exit is a good @@ -57,32 +58,35 @@ // In the rare contexts where every microsecond and every allocation matter, // use the Logger. It's even faster than the SugaredLogger and allocates far // less, but it only supports strongly-typed, structured logging. -// logger := zap.NewExample() -// defer logger.Sync() -// logger.Info("failed to fetch URL", -// zap.String("url", "http://example.com"), -// zap.Int("attempt", 3), -// zap.Duration("backoff", time.Second), -// ) +// +// logger := zap.NewExample() +// defer logger.Sync() +// logger.Info("failed to fetch URL", +// zap.String("url", "http://example.com"), +// zap.Int("attempt", 3), +// zap.Duration("backoff", time.Second), +// ) // // Choosing between the Logger and SugaredLogger doesn't need to be an // application-wide decision: converting between the two is simple and // inexpensive. -// logger := zap.NewExample() -// defer logger.Sync() -// sugar := logger.Sugar() -// plain := sugar.Desugar() // -// Configuring Zap +// logger := zap.NewExample() +// defer logger.Sync() +// sugar := logger.Sugar() +// plain := sugar.Desugar() +// +// # Configuring Zap // // The simplest way to build a Logger is to use zap's opinionated presets: // NewExample, NewProduction, and NewDevelopment. These presets build a logger // with a single function call: -// logger, err := zap.NewProduction() -// if err != nil { -// log.Fatalf("can't initialize zap logger: %v", err) -// } -// defer logger.Sync() +// +// logger, err := zap.NewProduction() +// if err != nil { +// log.Fatalf("can't initialize zap logger: %v", err) +// } +// defer logger.Sync() // // Presets are fine for small projects, but larger projects and organizations // naturally require a bit more customization. For most users, zap's Config @@ -94,7 +98,7 @@ // go.uber.org/zap/zapcore. See the package-level AdvancedConfiguration // example for sample code. // -// Extending Zap +// # Extending Zap // // The zap package itself is a relatively thin wrapper around the interfaces // in go.uber.org/zap/zapcore. Extending zap to support a new encoding (e.g., @@ -106,7 +110,7 @@ // Similarly, package authors can use the high-performance Encoder and Core // implementations in the zapcore package to build their own loggers. // -// Frequently Asked Questions +// # Frequently Asked Questions // // An FAQ covering everything from installation errors to design decisions is // available at https://github.com/uber-go/zap/blob/master/FAQ.md. diff --git a/vendor/go.uber.org/zap/encoder.go b/vendor/go.uber.org/zap/encoder.go index 08ed8335436..caa04ceefd8 100644 --- a/vendor/go.uber.org/zap/encoder.go +++ b/vendor/go.uber.org/zap/encoder.go @@ -63,7 +63,7 @@ func RegisterEncoder(name string, constructor func(zapcore.EncoderConfig) (zapco func newEncoder(name string, encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) { if encoderConfig.TimeKey != "" && encoderConfig.EncodeTime == nil { - return nil, fmt.Errorf("missing EncodeTime in EncoderConfig") + return nil, errors.New("missing EncodeTime in EncoderConfig") } _encoderMutex.RLock() diff --git a/vendor/go.uber.org/zap/error.go b/vendor/go.uber.org/zap/error.go index 65982a51e54..45f7b838dc1 100644 --- a/vendor/go.uber.org/zap/error.go +++ b/vendor/go.uber.org/zap/error.go @@ -21,14 +21,13 @@ package zap import ( - "sync" - + "go.uber.org/zap/internal/pool" "go.uber.org/zap/zapcore" ) -var _errArrayElemPool = sync.Pool{New: func() interface{} { +var _errArrayElemPool = pool.New(func() *errArrayElem { return &errArrayElem{} -}} +}) // Error is shorthand for the common idiom NamedError("error", err). func Error(err error) Field { @@ -60,11 +59,14 @@ func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error { // potentially an "errorVerbose" attribute, we need to wrap it in a // type that implements LogObjectMarshaler. To prevent this from // allocating, pool the wrapper type. - elem := _errArrayElemPool.Get().(*errArrayElem) + elem := _errArrayElemPool.Get() elem.error = errs[i] - arr.AppendObject(elem) + err := arr.AppendObject(elem) elem.error = nil _errArrayElemPool.Put(elem) + if err != nil { + return err + } } return nil } diff --git a/vendor/go.uber.org/zap/field.go b/vendor/go.uber.org/zap/field.go index bbb745db5bd..c8dd3358a9c 100644 --- a/vendor/go.uber.org/zap/field.go +++ b/vendor/go.uber.org/zap/field.go @@ -25,6 +25,7 @@ import ( "math" "time" + "go.uber.org/zap/internal/stacktrace" "go.uber.org/zap/zapcore" ) @@ -374,7 +375,7 @@ func StackSkip(key string, skip int) Field { // from expanding the zapcore.Field union struct to include a byte slice. Since // taking a stacktrace is already so expensive (~10us), the extra allocation // is okay. - return String(key, takeStacktrace(skip+1)) // skip StackSkip + return String(key, stacktrace.Take(skip+1)) // skip StackSkip } // Duration constructs a field with the given key and value. The encoder @@ -410,6 +411,63 @@ func Inline(val zapcore.ObjectMarshaler) Field { } } +// Dict constructs a field containing the provided key-value pairs. +// It acts similar to [Object], but with the fields specified as arguments. +func Dict(key string, val ...Field) Field { + return dictField(key, val) +} + +// We need a function with the signature (string, T) for zap.Any. +func dictField(key string, val []Field) Field { + return Object(key, dictObject(val)) +} + +type dictObject []Field + +func (d dictObject) MarshalLogObject(enc zapcore.ObjectEncoder) error { + for _, f := range d { + f.AddTo(enc) + } + return nil +} + +// We discovered an issue where zap.Any can cause a performance degradation +// when used in new goroutines. +// +// This happens because the compiler assigns 4.8kb (one zap.Field per arm of +// switch statement) of stack space for zap.Any when it takes the form: +// +// switch v := v.(type) { +// case string: +// return String(key, v) +// case int: +// return Int(key, v) +// // ... +// default: +// return Reflect(key, v) +// } +// +// To avoid this, we use the type switch to assign a value to a single local variable +// and then call a function on it. +// The local variable is just a function reference so it doesn't allocate +// when converted to an interface{}. +// +// A fair bit of experimentation went into this. +// See also: +// +// - https://github.com/uber-go/zap/pull/1301 +// - https://github.com/uber-go/zap/pull/1303 +// - https://github.com/uber-go/zap/pull/1304 +// - https://github.com/uber-go/zap/pull/1305 +// - https://github.com/uber-go/zap/pull/1308 +type anyFieldC[T any] func(string, T) Field + +func (f anyFieldC[T]) Any(key string, val any) Field { + v, _ := val.(T) + // val is guaranteed to be a T, except when it's nil. + return f(key, v) +} + // Any takes a key and an arbitrary value and chooses the best way to represent // them as a field, falling back to a reflection-based approach only if // necessary. @@ -418,132 +476,138 @@ func Inline(val zapcore.ObjectMarshaler) Field { // them. To minimize surprises, []byte values are treated as binary blobs, byte // values are treated as uint8, and runes are always treated as integers. func Any(key string, value interface{}) Field { - switch val := value.(type) { + var c interface{ Any(string, any) Field } + + switch value.(type) { case zapcore.ObjectMarshaler: - return Object(key, val) + c = anyFieldC[zapcore.ObjectMarshaler](Object) case zapcore.ArrayMarshaler: - return Array(key, val) + c = anyFieldC[zapcore.ArrayMarshaler](Array) + case []Field: + c = anyFieldC[[]Field](dictField) case bool: - return Bool(key, val) + c = anyFieldC[bool](Bool) case *bool: - return Boolp(key, val) + c = anyFieldC[*bool](Boolp) case []bool: - return Bools(key, val) + c = anyFieldC[[]bool](Bools) case complex128: - return Complex128(key, val) + c = anyFieldC[complex128](Complex128) case *complex128: - return Complex128p(key, val) + c = anyFieldC[*complex128](Complex128p) case []complex128: - return Complex128s(key, val) + c = anyFieldC[[]complex128](Complex128s) case complex64: - return Complex64(key, val) + c = anyFieldC[complex64](Complex64) case *complex64: - return Complex64p(key, val) + c = anyFieldC[*complex64](Complex64p) case []complex64: - return Complex64s(key, val) + c = anyFieldC[[]complex64](Complex64s) case float64: - return Float64(key, val) + c = anyFieldC[float64](Float64) case *float64: - return Float64p(key, val) + c = anyFieldC[*float64](Float64p) case []float64: - return Float64s(key, val) + c = anyFieldC[[]float64](Float64s) case float32: - return Float32(key, val) + c = anyFieldC[float32](Float32) case *float32: - return Float32p(key, val) + c = anyFieldC[*float32](Float32p) case []float32: - return Float32s(key, val) + c = anyFieldC[[]float32](Float32s) case int: - return Int(key, val) + c = anyFieldC[int](Int) case *int: - return Intp(key, val) + c = anyFieldC[*int](Intp) case []int: - return Ints(key, val) + c = anyFieldC[[]int](Ints) case int64: - return Int64(key, val) + c = anyFieldC[int64](Int64) case *int64: - return Int64p(key, val) + c = anyFieldC[*int64](Int64p) case []int64: - return Int64s(key, val) + c = anyFieldC[[]int64](Int64s) case int32: - return Int32(key, val) + c = anyFieldC[int32](Int32) case *int32: - return Int32p(key, val) + c = anyFieldC[*int32](Int32p) case []int32: - return Int32s(key, val) + c = anyFieldC[[]int32](Int32s) case int16: - return Int16(key, val) + c = anyFieldC[int16](Int16) case *int16: - return Int16p(key, val) + c = anyFieldC[*int16](Int16p) case []int16: - return Int16s(key, val) + c = anyFieldC[[]int16](Int16s) case int8: - return Int8(key, val) + c = anyFieldC[int8](Int8) case *int8: - return Int8p(key, val) + c = anyFieldC[*int8](Int8p) case []int8: - return Int8s(key, val) + c = anyFieldC[[]int8](Int8s) case string: - return String(key, val) + c = anyFieldC[string](String) case *string: - return Stringp(key, val) + c = anyFieldC[*string](Stringp) case []string: - return Strings(key, val) + c = anyFieldC[[]string](Strings) case uint: - return Uint(key, val) + c = anyFieldC[uint](Uint) case *uint: - return Uintp(key, val) + c = anyFieldC[*uint](Uintp) case []uint: - return Uints(key, val) + c = anyFieldC[[]uint](Uints) case uint64: - return Uint64(key, val) + c = anyFieldC[uint64](Uint64) case *uint64: - return Uint64p(key, val) + c = anyFieldC[*uint64](Uint64p) case []uint64: - return Uint64s(key, val) + c = anyFieldC[[]uint64](Uint64s) case uint32: - return Uint32(key, val) + c = anyFieldC[uint32](Uint32) case *uint32: - return Uint32p(key, val) + c = anyFieldC[*uint32](Uint32p) case []uint32: - return Uint32s(key, val) + c = anyFieldC[[]uint32](Uint32s) case uint16: - return Uint16(key, val) + c = anyFieldC[uint16](Uint16) case *uint16: - return Uint16p(key, val) + c = anyFieldC[*uint16](Uint16p) case []uint16: - return Uint16s(key, val) + c = anyFieldC[[]uint16](Uint16s) case uint8: - return Uint8(key, val) + c = anyFieldC[uint8](Uint8) case *uint8: - return Uint8p(key, val) + c = anyFieldC[*uint8](Uint8p) case []byte: - return Binary(key, val) + c = anyFieldC[[]byte](Binary) case uintptr: - return Uintptr(key, val) + c = anyFieldC[uintptr](Uintptr) case *uintptr: - return Uintptrp(key, val) + c = anyFieldC[*uintptr](Uintptrp) case []uintptr: - return Uintptrs(key, val) + c = anyFieldC[[]uintptr](Uintptrs) case time.Time: - return Time(key, val) + c = anyFieldC[time.Time](Time) case *time.Time: - return Timep(key, val) + c = anyFieldC[*time.Time](Timep) case []time.Time: - return Times(key, val) + c = anyFieldC[[]time.Time](Times) case time.Duration: - return Duration(key, val) + c = anyFieldC[time.Duration](Duration) case *time.Duration: - return Durationp(key, val) + c = anyFieldC[*time.Duration](Durationp) case []time.Duration: - return Durations(key, val) + c = anyFieldC[[]time.Duration](Durations) case error: - return NamedError(key, val) + c = anyFieldC[error](NamedError) case []error: - return Errors(key, val) + c = anyFieldC[[]error](Errors) case fmt.Stringer: - return Stringer(key, val) + c = anyFieldC[fmt.Stringer](Stringer) default: - return Reflect(key, val) + c = anyFieldC[any](Reflect) } + + return c.Any(key, value) } diff --git a/vendor/go.uber.org/zap/global.go b/vendor/go.uber.org/zap/global.go index c1ac0507cd9..3cb46c9e0ac 100644 --- a/vendor/go.uber.org/zap/global.go +++ b/vendor/go.uber.org/zap/global.go @@ -31,6 +31,7 @@ import ( ) const ( + _stdLogDefaultDepth = 1 _loggerWriterDepth = 2 _programmerErrorTemplate = "You've found a bug in zap! Please file a bug at " + "https://github.com/uber-go/zap/issues/new and reference this error: %v" diff --git a/vendor/go.uber.org/zap/global_prego112.go b/vendor/go.uber.org/zap/global_prego112.go deleted file mode 100644 index d3ab9af933e..00000000000 --- a/vendor/go.uber.org/zap/global_prego112.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2019 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// See #682 for more information. -// +build !go1.12 - -package zap - -const _stdLogDefaultDepth = 2 diff --git a/vendor/go.uber.org/zap/http_handler.go b/vendor/go.uber.org/zap/http_handler.go index 1297c33b328..2be8f651500 100644 --- a/vendor/go.uber.org/zap/http_handler.go +++ b/vendor/go.uber.org/zap/http_handler.go @@ -22,6 +22,7 @@ package zap import ( "encoding/json" + "errors" "fmt" "io" "net/http" @@ -32,22 +33,23 @@ import ( // ServeHTTP is a simple JSON endpoint that can report on or change the current // logging level. // -// GET +// # GET // // The GET request returns a JSON description of the current logging level like: -// {"level":"info"} // -// PUT +// {"level":"info"} +// +// # PUT // // The PUT request changes the logging level. It is perfectly safe to change the // logging level while a program is running. Two content types are supported: // -// Content-Type: application/x-www-form-urlencoded +// Content-Type: application/x-www-form-urlencoded // // With this content type, the level can be provided through the request body or // a query parameter. The log level is URL encoded like: // -// level=debug +// level=debug // // The request body takes precedence over the query parameter, if both are // specified. @@ -55,19 +57,25 @@ import ( // This content type is the default for a curl PUT request. Following are two // example curl requests that both set the logging level to debug. // -// curl -X PUT localhost:8080/log/level?level=debug -// curl -X PUT localhost:8080/log/level -d level=debug +// curl -X PUT localhost:8080/log/level?level=debug +// curl -X PUT localhost:8080/log/level -d level=debug // // For any other content type, the payload is expected to be JSON encoded and // look like: // -// {"level":"info"} +// {"level":"info"} // // An example curl request could look like this: // -// curl -X PUT localhost:8080/log/level -H "Content-Type: application/json" -d '{"level":"debug"}' -// +// curl -X PUT localhost:8080/log/level -H "Content-Type: application/json" -d '{"level":"debug"}' func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if err := lvl.serveHTTP(w, r); err != nil { + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "internal error: %v", err) + } +} + +func (lvl AtomicLevel) serveHTTP(w http.ResponseWriter, r *http.Request) error { type errorResponse struct { Error string `json:"error"` } @@ -79,19 +87,20 @@ func (lvl AtomicLevel) ServeHTTP(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: - enc.Encode(payload{Level: lvl.Level()}) + return enc.Encode(payload{Level: lvl.Level()}) + case http.MethodPut: requestedLvl, err := decodePutRequest(r.Header.Get("Content-Type"), r) if err != nil { w.WriteHeader(http.StatusBadRequest) - enc.Encode(errorResponse{Error: err.Error()}) - return + return enc.Encode(errorResponse{Error: err.Error()}) } lvl.SetLevel(requestedLvl) - enc.Encode(payload{Level: lvl.Level()}) + return enc.Encode(payload{Level: lvl.Level()}) + default: w.WriteHeader(http.StatusMethodNotAllowed) - enc.Encode(errorResponse{ + return enc.Encode(errorResponse{ Error: "Only GET and PUT are supported.", }) } @@ -108,7 +117,7 @@ func decodePutRequest(contentType string, r *http.Request) (zapcore.Level, error func decodePutURL(r *http.Request) (zapcore.Level, error) { lvl := r.FormValue("level") if lvl == "" { - return 0, fmt.Errorf("must specify logging level") + return 0, errors.New("must specify logging level") } var l zapcore.Level if err := l.UnmarshalText([]byte(lvl)); err != nil { @@ -125,8 +134,7 @@ func decodePutJSON(body io.Reader) (zapcore.Level, error) { return 0, fmt.Errorf("malformed request body: %v", err) } if pld.Level == nil { - return 0, fmt.Errorf("must specify logging level") + return 0, errors.New("must specify logging level") } return *pld.Level, nil - } diff --git a/vendor/go.uber.org/zap/internal/exit/exit.go b/vendor/go.uber.org/zap/internal/exit/exit.go index dfc5b05feb7..f673f9947b8 100644 --- a/vendor/go.uber.org/zap/internal/exit/exit.go +++ b/vendor/go.uber.org/zap/internal/exit/exit.go @@ -24,24 +24,25 @@ package exit import "os" -var real = func() { os.Exit(1) } +var _exit = os.Exit -// Exit normally terminates the process by calling os.Exit(1). If the package -// is stubbed, it instead records a call in the testing spy. -func Exit() { - real() +// With terminates the process by calling os.Exit(code). If the package is +// stubbed, it instead records a call in the testing spy. +func With(code int) { + _exit(code) } // A StubbedExit is a testing fake for os.Exit. type StubbedExit struct { Exited bool - prev func() + Code int + prev func(code int) } // Stub substitutes a fake for the call to os.Exit(1). func Stub() *StubbedExit { - s := &StubbedExit{prev: real} - real = s.exit + s := &StubbedExit{prev: _exit} + _exit = s.exit return s } @@ -56,9 +57,10 @@ func WithStub(f func()) *StubbedExit { // Unstub restores the previous exit function. func (se *StubbedExit) Unstub() { - real = se.prev + _exit = se.prev } -func (se *StubbedExit) exit() { +func (se *StubbedExit) exit(code int) { se.Exited = true + se.Code = code } diff --git a/vendor/go.uber.org/atomic/error_ext.go b/vendor/go.uber.org/zap/internal/level_enabler.go similarity index 65% rename from vendor/go.uber.org/atomic/error_ext.go rename to vendor/go.uber.org/zap/internal/level_enabler.go index ffe0be21cb0..40bfed81e6e 100644 --- a/vendor/go.uber.org/atomic/error_ext.go +++ b/vendor/go.uber.org/zap/internal/level_enabler.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Uber Technologies, Inc. +// Copyright (c) 2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,22 +18,20 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package atomic +// Package internal and its subpackages hold types and functionality +// that are not part of Zap's public API. +package internal -// atomic.Value panics on nil inputs, or if the underlying type changes. -// Stabilize by always storing a custom struct that we control. +import "go.uber.org/zap/zapcore" -//go:generate bin/gen-atomicwrapper -name=Error -type=error -wrapped=Value -pack=packError -unpack=unpackError -file=error.go - -type packedError struct{ Value error } - -func packError(v error) interface{} { - return packedError{v} -} +// LeveledEnabler is an interface satisfied by LevelEnablers that are able to +// report their own level. +// +// This interface is defined to use more conveniently in tests and non-zapcore +// packages. +// This cannot be imported from zapcore because of the cyclic dependency. +type LeveledEnabler interface { + zapcore.LevelEnabler -func unpackError(v interface{}) error { - if err, ok := v.(packedError); ok { - return err.Value - } - return nil + Level() zapcore.Level } diff --git a/vendor/go.uber.org/atomic/error.go b/vendor/go.uber.org/zap/internal/pool/pool.go similarity index 55% rename from vendor/go.uber.org/atomic/error.go rename to vendor/go.uber.org/zap/internal/pool/pool.go index a6166fbea01..60e9d2c432d 100644 --- a/vendor/go.uber.org/atomic/error.go +++ b/vendor/go.uber.org/zap/internal/pool/pool.go @@ -1,6 +1,4 @@ -// @generated Code generated by gen-atomicwrapper. - -// Copyright (c) 2020 Uber Technologies, Inc. +// Copyright (c) 2023 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -20,32 +18,41 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package atomic +// Package pool provides internal pool utilities. +package pool -// Error is an atomic type-safe wrapper for error values. -type Error struct { - _ nocmp // disallow non-atomic comparison +import ( + "sync" +) - v Value +// A Pool is a generic wrapper around [sync.Pool] to provide strongly-typed +// object pooling. +// +// Note that SA6002 (ref: https://staticcheck.io/docs/checks/#SA6002) will +// not be detected, so all internal pool use must take care to only store +// pointer types. +type Pool[T any] struct { + pool sync.Pool } -var _zeroError error - -// NewError creates a new Error. -func NewError(v error) *Error { - x := &Error{} - if v != _zeroError { - x.Store(v) +// New returns a new [Pool] for T, and will use fn to construct new Ts when +// the pool is empty. +func New[T any](fn func() T) *Pool[T] { + return &Pool[T]{ + pool: sync.Pool{ + New: func() any { + return fn() + }, + }, } - return x } -// Load atomically loads the wrapped error. -func (x *Error) Load() error { - return unpackError(x.v.Load()) +// Get gets a T from the pool, or creates a new one if the pool is empty. +func (p *Pool[T]) Get() T { + return p.pool.Get().(T) } -// Store atomically stores the passed error. -func (x *Error) Store(v error) { - x.v.Store(packError(v)) +// Put returns x into the pool. +func (p *Pool[T]) Put(x T) { + p.pool.Put(x) } diff --git a/vendor/go.uber.org/zap/internal/stacktrace/stack.go b/vendor/go.uber.org/zap/internal/stacktrace/stack.go new file mode 100644 index 00000000000..82af7551f93 --- /dev/null +++ b/vendor/go.uber.org/zap/internal/stacktrace/stack.go @@ -0,0 +1,181 @@ +// Copyright (c) 2023 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// Package stacktrace provides support for gathering stack traces +// efficiently. +package stacktrace + +import ( + "runtime" + + "go.uber.org/zap/buffer" + "go.uber.org/zap/internal/bufferpool" + "go.uber.org/zap/internal/pool" +) + +var _stackPool = pool.New(func() *Stack { + return &Stack{ + storage: make([]uintptr, 64), + } +}) + +// Stack is a captured stack trace. +type Stack struct { + pcs []uintptr // program counters; always a subslice of storage + frames *runtime.Frames + + // The size of pcs varies depending on requirements: + // it will be one if the only the first frame was requested, + // and otherwise it will reflect the depth of the call stack. + // + // storage decouples the slice we need (pcs) from the slice we pool. + // We will always allocate a reasonably large storage, but we'll use + // only as much of it as we need. + storage []uintptr +} + +// Depth specifies how deep of a stack trace should be captured. +type Depth int + +const ( + // First captures only the first frame. + First Depth = iota + + // Full captures the entire call stack, allocating more + // storage for it if needed. + Full +) + +// Capture captures a stack trace of the specified depth, skipping +// the provided number of frames. skip=0 identifies the caller of +// Capture. +// +// The caller must call Free on the returned stacktrace after using it. +func Capture(skip int, depth Depth) *Stack { + stack := _stackPool.Get() + + switch depth { + case First: + stack.pcs = stack.storage[:1] + case Full: + stack.pcs = stack.storage + } + + // Unlike other "skip"-based APIs, skip=0 identifies runtime.Callers + // itself. +2 to skip captureStacktrace and runtime.Callers. + numFrames := runtime.Callers( + skip+2, + stack.pcs, + ) + + // runtime.Callers truncates the recorded stacktrace if there is no + // room in the provided slice. For the full stack trace, keep expanding + // storage until there are fewer frames than there is room. + if depth == Full { + pcs := stack.pcs + for numFrames == len(pcs) { + pcs = make([]uintptr, len(pcs)*2) + numFrames = runtime.Callers(skip+2, pcs) + } + + // Discard old storage instead of returning it to the pool. + // This will adjust the pool size over time if stack traces are + // consistently very deep. + stack.storage = pcs + stack.pcs = pcs[:numFrames] + } else { + stack.pcs = stack.pcs[:numFrames] + } + + stack.frames = runtime.CallersFrames(stack.pcs) + return stack +} + +// Free releases resources associated with this stacktrace +// and returns it back to the pool. +func (st *Stack) Free() { + st.frames = nil + st.pcs = nil + _stackPool.Put(st) +} + +// Count reports the total number of frames in this stacktrace. +// Count DOES NOT change as Next is called. +func (st *Stack) Count() int { + return len(st.pcs) +} + +// Next returns the next frame in the stack trace, +// and a boolean indicating whether there are more after it. +func (st *Stack) Next() (_ runtime.Frame, more bool) { + return st.frames.Next() +} + +// Take returns a string representation of the current stacktrace. +// +// skip is the number of frames to skip before recording the stack trace. +// skip=0 identifies the caller of Take. +func Take(skip int) string { + stack := Capture(skip+1, Full) + defer stack.Free() + + buffer := bufferpool.Get() + defer buffer.Free() + + stackfmt := NewFormatter(buffer) + stackfmt.FormatStack(stack) + return buffer.String() +} + +// Formatter formats a stack trace into a readable string representation. +type Formatter struct { + b *buffer.Buffer + nonEmpty bool // whehther we've written at least one frame already +} + +// NewFormatter builds a new Formatter. +func NewFormatter(b *buffer.Buffer) Formatter { + return Formatter{b: b} +} + +// FormatStack formats all remaining frames in the provided stacktrace -- minus +// the final runtime.main/runtime.goexit frame. +func (sf *Formatter) FormatStack(stack *Stack) { + // Note: On the last iteration, frames.Next() returns false, with a valid + // frame, but we ignore this frame. The last frame is a runtime frame which + // adds noise, since it's only either runtime.main or runtime.goexit. + for frame, more := stack.Next(); more; frame, more = stack.Next() { + sf.FormatFrame(frame) + } +} + +// FormatFrame formats the given frame. +func (sf *Formatter) FormatFrame(frame runtime.Frame) { + if sf.nonEmpty { + sf.b.AppendByte('\n') + } + sf.nonEmpty = true + sf.b.AppendString(frame.Function) + sf.b.AppendByte('\n') + sf.b.AppendByte('\t') + sf.b.AppendString(frame.File) + sf.b.AppendByte(':') + sf.b.AppendInt(int64(frame.Line)) +} diff --git a/vendor/go.uber.org/zap/level.go b/vendor/go.uber.org/zap/level.go index 3567a9a1e6a..155b208bd3c 100644 --- a/vendor/go.uber.org/zap/level.go +++ b/vendor/go.uber.org/zap/level.go @@ -21,7 +21,9 @@ package zap import ( - "go.uber.org/atomic" + "sync/atomic" + + "go.uber.org/zap/internal" "go.uber.org/zap/zapcore" ) @@ -70,12 +72,14 @@ type AtomicLevel struct { l *atomic.Int32 } +var _ internal.LeveledEnabler = AtomicLevel{} + // NewAtomicLevel creates an AtomicLevel with InfoLevel and above logging // enabled. func NewAtomicLevel() AtomicLevel { - return AtomicLevel{ - l: atomic.NewInt32(int32(InfoLevel)), - } + lvl := AtomicLevel{l: new(atomic.Int32)} + lvl.l.Store(int32(InfoLevel)) + return lvl } // NewAtomicLevelAt is a convenience function that creates an AtomicLevel @@ -86,6 +90,23 @@ func NewAtomicLevelAt(l zapcore.Level) AtomicLevel { return a } +// ParseAtomicLevel parses an AtomicLevel based on a lowercase or all-caps ASCII +// representation of the log level. If the provided ASCII representation is +// invalid an error is returned. +// +// This is particularly useful when dealing with text input to configure log +// levels. +func ParseAtomicLevel(text string) (AtomicLevel, error) { + a := NewAtomicLevel() + l, err := zapcore.ParseLevel(text) + if err != nil { + return a, err + } + + a.SetLevel(l) + return a, nil +} + // Enabled implements the zapcore.LevelEnabler interface, which allows the // AtomicLevel to be used in place of traditional static levels. func (lvl AtomicLevel) Enabled(l zapcore.Level) bool { diff --git a/vendor/go.uber.org/zap/logger.go b/vendor/go.uber.org/zap/logger.go index f116bd936fe..6205fe48a6c 100644 --- a/vendor/go.uber.org/zap/logger.go +++ b/vendor/go.uber.org/zap/logger.go @@ -22,11 +22,12 @@ package zap import ( "fmt" - "io/ioutil" + "io" "os" - "runtime" "strings" + "go.uber.org/zap/internal/bufferpool" + "go.uber.org/zap/internal/stacktrace" "go.uber.org/zap/zapcore" ) @@ -42,7 +43,7 @@ type Logger struct { development bool addCaller bool - onFatal zapcore.CheckWriteAction // default is WriteThenFatal + onFatal zapcore.CheckWriteHook // default is WriteThenFatal name string errorOutput zapcore.WriteSyncer @@ -85,7 +86,7 @@ func New(core zapcore.Core, options ...Option) *Logger { func NewNop() *Logger { return &Logger{ core: zapcore.NewNopCore(), - errorOutput: zapcore.AddSync(ioutil.Discard), + errorOutput: zapcore.AddSync(io.Discard), addStack: zapcore.FatalLevel + 1, clock: zapcore.DefaultClock, } @@ -107,6 +108,19 @@ func NewDevelopment(options ...Option) (*Logger, error) { return NewDevelopmentConfig().Build(options...) } +// Must is a helper that wraps a call to a function returning (*Logger, error) +// and panics if the error is non-nil. It is intended for use in variable +// initialization such as: +// +// var logger = zap.Must(zap.NewProduction()) +func Must(logger *Logger, err error) *Logger { + if err != nil { + panic(err) + } + + return logger +} + // NewExample builds a Logger that's designed for use in zap's testable // examples. It writes DebugLevel and above logs to standard out as JSON, but // omits the timestamp and calling function to keep example output @@ -160,7 +174,8 @@ func (log *Logger) WithOptions(opts ...Option) *Logger { } // With creates a child logger and adds structured context to it. Fields added -// to the child don't affect the parent, and vice versa. +// to the child don't affect the parent, and vice versa. Any fields that +// require evaluation (such as Objects) are evaluated upon invocation of With. func (log *Logger) With(fields ...Field) *Logger { if len(fields) == 0 { return log @@ -170,6 +185,35 @@ func (log *Logger) With(fields ...Field) *Logger { return l } +// WithLazy creates a child logger and adds structured context to it lazily. +// +// The fields are evaluated only if the logger is further chained with [With] +// or is written to with any of the log level methods. +// Until that occurs, the logger may retain references to objects inside the fields, +// and logging will reflect the state of an object at the time of logging, +// not the time of WithLazy(). +// +// WithLazy provides a worthwhile performance optimization for contextual loggers +// when the likelihood of using the child logger is low, +// such as error paths and rarely taken branches. +// +// Similar to [With], fields added to the child don't affect the parent, and vice versa. +func (log *Logger) WithLazy(fields ...Field) *Logger { + if len(fields) == 0 { + return log + } + return log.WithOptions(WrapCore(func(core zapcore.Core) zapcore.Core { + return zapcore.NewLazyWith(core, fields) + })) +} + +// Level reports the minimum enabled level for this logger. +// +// For NopLoggers, this is [zapcore.InvalidLevel]. +func (log *Logger) Level() zapcore.Level { + return zapcore.LevelOf(log.core) +} + // Check returns a CheckedEntry if logging a message at the specified level // is enabled. It's a completely optional optimization; in high-performance // applications, Check can help avoid allocating a slice to hold fields. @@ -177,6 +221,16 @@ func (log *Logger) Check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { return log.check(lvl, msg) } +// Log logs a message at the specified level. The message includes any fields +// passed at the log site, as well as any fields accumulated on the logger. +// Any Fields that require evaluation (such as Objects) are evaluated upon +// invocation of Log. +func (log *Logger) Log(lvl zapcore.Level, msg string, fields ...Field) { + if ce := log.check(lvl, msg); ce != nil { + ce.Write(fields...) + } +} + // Debug logs a message at DebugLevel. The message includes any fields passed // at the log site, as well as any fields accumulated on the logger. func (log *Logger) Debug(msg string, fields ...Field) { @@ -253,14 +307,22 @@ func (log *Logger) Core() zapcore.Core { return log.core } +// Name returns the Logger's underlying name, +// or an empty string if the logger is unnamed. +func (log *Logger) Name() string { + return log.name +} + func (log *Logger) clone() *Logger { - copy := *log - return © + clone := *log + return &clone } func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { - // check must always be called directly by a method in the Logger interface - // (e.g., Check, Info, Fatal). + // Logger.check must always be called directly by a method in the + // Logger interface (e.g., Check, Info, Fatal). + // This skips Logger.check and the Info/Fatal/Check/etc. method that + // called it. const callerSkipOffset = 2 // Check the level first to reduce the cost of disabled log calls. @@ -283,18 +345,27 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { // Set up any required terminal behavior. switch ent.Level { case zapcore.PanicLevel: - ce = ce.Should(ent, zapcore.WriteThenPanic) + ce = ce.After(ent, zapcore.WriteThenPanic) case zapcore.FatalLevel: onFatal := log.onFatal - // Noop is the default value for CheckWriteAction, and it leads to - // continued execution after a Fatal which is unexpected. - if onFatal == zapcore.WriteThenNoop { + // nil or WriteThenNoop will lead to continued execution after + // a Fatal log entry, which is unexpected. For example, + // + // f, err := os.Open(..) + // if err != nil { + // log.Fatal("cannot open", zap.Error(err)) + // } + // fmt.Println(f.Name()) + // + // The f.Name() will panic if we continue execution after the + // log.Fatal. + if onFatal == nil || onFatal == zapcore.WriteThenNoop { onFatal = zapcore.WriteThenFatal } - ce = ce.Should(ent, onFatal) + ce = ce.After(ent, onFatal) case zapcore.DPanicLevel: if log.development { - ce = ce.Should(ent, zapcore.WriteThenPanic) + ce = ce.After(ent, zapcore.WriteThenPanic) } } @@ -307,42 +378,55 @@ func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { // Thread the error output through to the CheckedEntry. ce.ErrorOutput = log.errorOutput - if log.addCaller { - frame, defined := getCallerFrame(log.callerSkip + callerSkipOffset) - if !defined { + + addStack := log.addStack.Enabled(ce.Level) + if !log.addCaller && !addStack { + return ce + } + + // Adding the caller or stack trace requires capturing the callers of + // this function. We'll share information between these two. + stackDepth := stacktrace.First + if addStack { + stackDepth = stacktrace.Full + } + stack := stacktrace.Capture(log.callerSkip+callerSkipOffset, stackDepth) + defer stack.Free() + + if stack.Count() == 0 { + if log.addCaller { fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", ent.Time.UTC()) - log.errorOutput.Sync() + _ = log.errorOutput.Sync() } + return ce + } + + frame, more := stack.Next() - ce.Entry.Caller = zapcore.EntryCaller{ - Defined: defined, + if log.addCaller { + ce.Caller = zapcore.EntryCaller{ + Defined: frame.PC != 0, PC: frame.PC, File: frame.File, Line: frame.Line, Function: frame.Function, } } - if log.addStack.Enabled(ce.Entry.Level) { - ce.Entry.Stack = StackSkip("", log.callerSkip+callerSkipOffset).String - } - return ce -} + if addStack { + buffer := bufferpool.Get() + defer buffer.Free() -// getCallerFrame gets caller frame. The argument skip is the number of stack -// frames to ascend, with 0 identifying the caller of getCallerFrame. The -// boolean ok is false if it was not possible to recover the information. -// -// Note: This implementation is similar to runtime.Caller, but it returns the whole frame. -func getCallerFrame(skip int) (frame runtime.Frame, ok bool) { - const skipOffset = 2 // skip getCallerFrame and Callers - - pc := make([]uintptr, 1) - numFrames := runtime.Callers(skip+skipOffset, pc) - if numFrames < 1 { - return + stackfmt := stacktrace.NewFormatter(buffer) + + // We've already extracted the first frame, so format that + // separately and defer to stackfmt for the rest. + stackfmt.FormatFrame(frame) + if more { + stackfmt.FormatStack(stack) + } + ce.Stack = buffer.String() } - frame, _ = runtime.CallersFrames(pc).Next() - return frame, frame.PC != 0 + return ce } diff --git a/vendor/go.uber.org/zap/options.go b/vendor/go.uber.org/zap/options.go index e9e66161f51..c4f3bca3d20 100644 --- a/vendor/go.uber.org/zap/options.go +++ b/vendor/go.uber.org/zap/options.go @@ -133,9 +133,28 @@ func IncreaseLevel(lvl zapcore.LevelEnabler) Option { } // OnFatal sets the action to take on fatal logs. +// +// Deprecated: Use [WithFatalHook] instead. func OnFatal(action zapcore.CheckWriteAction) Option { + return WithFatalHook(action) +} + +// WithFatalHook sets a CheckWriteHook to run on fatal logs. +// Zap will call this hook after writing a log statement with a Fatal level. +// +// For example, the following builds a logger that will exit the current +// goroutine after writing a fatal log message, but it will not exit the +// program. +// +// zap.New(core, zap.WithFatalHook(zapcore.WriteThenGoexit)) +// +// It is important that the provided CheckWriteHook stops the control flow at +// the current statement to meet expectations of callers of the logger. +// We recommend calling os.Exit or runtime.Goexit inside custom hooks at +// minimum. +func WithFatalHook(hook zapcore.CheckWriteHook) Option { return optionFunc(func(log *Logger) { - log.onFatal = action + log.onFatal = hook }) } diff --git a/vendor/go.uber.org/zap/sink.go b/vendor/go.uber.org/zap/sink.go index df46fa87a70..499772a00dc 100644 --- a/vendor/go.uber.org/zap/sink.go +++ b/vendor/go.uber.org/zap/sink.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2016-2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ import ( "io" "net/url" "os" + "path/filepath" "strings" "sync" @@ -34,23 +35,7 @@ import ( const schemeFile = "file" -var ( - _sinkMutex sync.RWMutex - _sinkFactories map[string]func(*url.URL) (Sink, error) // keyed by scheme -) - -func init() { - resetSinkRegistry() -} - -func resetSinkRegistry() { - _sinkMutex.Lock() - defer _sinkMutex.Unlock() - - _sinkFactories = map[string]func(*url.URL) (Sink, error){ - schemeFile: newFileSink, - } -} +var _sinkRegistry = newSinkRegistry() // Sink defines the interface to write to and close logger destinations. type Sink interface { @@ -58,10 +43,6 @@ type Sink interface { io.Closer } -type nopCloserSink struct{ zapcore.WriteSyncer } - -func (nopCloserSink) Close() error { return nil } - type errSinkNotFound struct { scheme string } @@ -70,16 +51,30 @@ func (e *errSinkNotFound) Error() string { return fmt.Sprintf("no sink found for scheme %q", e.scheme) } -// RegisterSink registers a user-supplied factory for all sinks with a -// particular scheme. -// -// All schemes must be ASCII, valid under section 3.1 of RFC 3986 -// (https://tools.ietf.org/html/rfc3986#section-3.1), and must not already -// have a factory registered. Zap automatically registers a factory for the -// "file" scheme. -func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { - _sinkMutex.Lock() - defer _sinkMutex.Unlock() +type nopCloserSink struct{ zapcore.WriteSyncer } + +func (nopCloserSink) Close() error { return nil } + +type sinkRegistry struct { + mu sync.Mutex + factories map[string]func(*url.URL) (Sink, error) // keyed by scheme + openFile func(string, int, os.FileMode) (*os.File, error) // type matches os.OpenFile +} + +func newSinkRegistry() *sinkRegistry { + sr := &sinkRegistry{ + factories: make(map[string]func(*url.URL) (Sink, error)), + openFile: os.OpenFile, + } + // Infallible operation: the registry is empty, so we can't have a conflict. + _ = sr.RegisterSink(schemeFile, sr.newFileSinkFromURL) + return sr +} + +// RegisterScheme registers the given factory for the specific scheme. +func (sr *sinkRegistry) RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { + sr.mu.Lock() + defer sr.mu.Unlock() if scheme == "" { return errors.New("can't register a sink factory for empty string") @@ -88,14 +83,22 @@ func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { if err != nil { return fmt.Errorf("%q is not a valid scheme: %v", scheme, err) } - if _, ok := _sinkFactories[normalized]; ok { + if _, ok := sr.factories[normalized]; ok { return fmt.Errorf("sink factory already registered for scheme %q", normalized) } - _sinkFactories[normalized] = factory + sr.factories[normalized] = factory return nil } -func newSink(rawURL string) (Sink, error) { +func (sr *sinkRegistry) newSink(rawURL string) (Sink, error) { + // URL parsing doesn't work well for Windows paths such as `c:\log.txt`, as scheme is set to + // the drive, and path is unset unless `c:/log.txt` is used. + // To avoid Windows-specific URL handling, we instead check IsAbs to open as a file. + // filepath.IsAbs is OS-specific, so IsAbs('c:/log.txt') is false outside of Windows. + if filepath.IsAbs(rawURL) { + return sr.newFileSinkFromPath(rawURL) + } + u, err := url.Parse(rawURL) if err != nil { return nil, fmt.Errorf("can't parse %q as a URL: %v", rawURL, err) @@ -104,16 +107,27 @@ func newSink(rawURL string) (Sink, error) { u.Scheme = schemeFile } - _sinkMutex.RLock() - factory, ok := _sinkFactories[u.Scheme] - _sinkMutex.RUnlock() + sr.mu.Lock() + factory, ok := sr.factories[u.Scheme] + sr.mu.Unlock() if !ok { return nil, &errSinkNotFound{u.Scheme} } return factory(u) } -func newFileSink(u *url.URL) (Sink, error) { +// RegisterSink registers a user-supplied factory for all sinks with a +// particular scheme. +// +// All schemes must be ASCII, valid under section 0.1 of RFC 3986 +// (https://tools.ietf.org/html/rfc3983#section-3.1), and must not already +// have a factory registered. Zap automatically registers a factory for the +// "file" scheme. +func RegisterSink(scheme string, factory func(*url.URL) (Sink, error)) error { + return _sinkRegistry.RegisterSink(scheme, factory) +} + +func (sr *sinkRegistry) newFileSinkFromURL(u *url.URL) (Sink, error) { if u.User != nil { return nil, fmt.Errorf("user and password not allowed with file URLs: got %v", u) } @@ -130,13 +144,18 @@ func newFileSink(u *url.URL) (Sink, error) { if hn := u.Hostname(); hn != "" && hn != "localhost" { return nil, fmt.Errorf("file URLs must leave host empty or use localhost: got %v", u) } - switch u.Path { + + return sr.newFileSinkFromPath(u.Path) +} + +func (sr *sinkRegistry) newFileSinkFromPath(path string) (Sink, error) { + switch path { case "stdout": return nopCloserSink{os.Stdout}, nil case "stderr": return nopCloserSink{os.Stderr}, nil } - return os.OpenFile(u.Path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666) + return sr.openFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o666) } func normalizeScheme(s string) (string, error) { diff --git a/vendor/go.uber.org/zap/stacktrace.go b/vendor/go.uber.org/zap/stacktrace.go deleted file mode 100644 index 0cf8c1ddffa..00000000000 --- a/vendor/go.uber.org/zap/stacktrace.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2016 Uber Technologies, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -package zap - -import ( - "runtime" - "sync" - - "go.uber.org/zap/internal/bufferpool" -) - -var ( - _stacktracePool = sync.Pool{ - New: func() interface{} { - return newProgramCounters(64) - }, - } -) - -func takeStacktrace(skip int) string { - buffer := bufferpool.Get() - defer buffer.Free() - programCounters := _stacktracePool.Get().(*programCounters) - defer _stacktracePool.Put(programCounters) - - var numFrames int - for { - // Skip the call to runtime.Callers and takeStacktrace so that the - // program counters start at the caller of takeStacktrace. - numFrames = runtime.Callers(skip+2, programCounters.pcs) - if numFrames < len(programCounters.pcs) { - break - } - // Don't put the too-short counter slice back into the pool; this lets - // the pool adjust if we consistently take deep stacktraces. - programCounters = newProgramCounters(len(programCounters.pcs) * 2) - } - - i := 0 - frames := runtime.CallersFrames(programCounters.pcs[:numFrames]) - - // Note: On the last iteration, frames.Next() returns false, with a valid - // frame, but we ignore this frame. The last frame is a a runtime frame which - // adds noise, since it's only either runtime.main or runtime.goexit. - for frame, more := frames.Next(); more; frame, more = frames.Next() { - if i != 0 { - buffer.AppendByte('\n') - } - i++ - buffer.AppendString(frame.Function) - buffer.AppendByte('\n') - buffer.AppendByte('\t') - buffer.AppendString(frame.File) - buffer.AppendByte(':') - buffer.AppendInt(int64(frame.Line)) - } - - return buffer.String() -} - -type programCounters struct { - pcs []uintptr -} - -func newProgramCounters(size int) *programCounters { - return &programCounters{make([]uintptr, size)} -} diff --git a/vendor/go.uber.org/zap/sugar.go b/vendor/go.uber.org/zap/sugar.go index 0b9651981a9..00ac5fe3ac8 100644 --- a/vendor/go.uber.org/zap/sugar.go +++ b/vendor/go.uber.org/zap/sugar.go @@ -31,6 +31,7 @@ import ( const ( _oddNumberErrMsg = "Ignored key without a value." _nonStringKeyErrMsg = "Ignored key-value pairs with non-string keys." + _multipleErrMsg = "Multiple errors without a key." ) // A SugaredLogger wraps the base Logger functionality in a slower, but less @@ -38,10 +39,19 @@ const ( // method. // // Unlike the Logger, the SugaredLogger doesn't insist on structured logging. -// For each log level, it exposes three methods: one for loosely-typed -// structured logging, one for println-style formatting, and one for -// printf-style formatting. For example, SugaredLoggers can produce InfoLevel -// output with Infow ("info with" structured context), Info, or Infof. +// For each log level, it exposes four methods: +// +// - methods named after the log level for log.Print-style logging +// - methods ending in "w" for loosely-typed structured logging +// - methods ending in "f" for log.Printf-style logging +// - methods ending in "ln" for log.Println-style logging +// +// For example, the methods for InfoLevel are: +// +// Info(...any) Print-style logging +// Infow(...any) Structured logging (read as "info with") +// Infof(string, ...any) Printf-style logging +// Infoln(...any) Println-style logging type SugaredLogger struct { base *Logger } @@ -61,27 +71,40 @@ func (s *SugaredLogger) Named(name string) *SugaredLogger { return &SugaredLogger{base: s.base.Named(name)} } +// WithOptions clones the current SugaredLogger, applies the supplied Options, +// and returns the result. It's safe to use concurrently. +func (s *SugaredLogger) WithOptions(opts ...Option) *SugaredLogger { + base := s.base.clone() + for _, opt := range opts { + opt.apply(base) + } + return &SugaredLogger{base: base} +} + // With adds a variadic number of fields to the logging context. It accepts a // mix of strongly-typed Field objects and loosely-typed key-value pairs. When // processing pairs, the first element of the pair is used as the field key // and the second as the field value. // // For example, -// sugaredLogger.With( -// "hello", "world", -// "failure", errors.New("oh no"), -// Stack(), -// "count", 42, -// "user", User{Name: "alice"}, -// ) +// +// sugaredLogger.With( +// "hello", "world", +// "failure", errors.New("oh no"), +// Stack(), +// "count", 42, +// "user", User{Name: "alice"}, +// ) +// // is the equivalent of -// unsugared.With( -// String("hello", "world"), -// String("failure", "oh no"), -// Stack(), -// Int("count", 42), -// Object("user", User{Name: "alice"}), -// ) +// +// unsugared.With( +// String("hello", "world"), +// String("failure", "oh no"), +// Stack(), +// Int("count", 42), +// Object("user", User{Name: "alice"}), +// ) // // Note that the keys in key-value pairs should be strings. In development, // passing a non-string key panics. In production, the logger is more @@ -92,74 +115,95 @@ func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger { return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)} } -// Debug uses fmt.Sprint to construct and log a message. +// Level reports the minimum enabled level for this logger. +// +// For NopLoggers, this is [zapcore.InvalidLevel]. +func (s *SugaredLogger) Level() zapcore.Level { + return zapcore.LevelOf(s.base.core) +} + +// Debug logs the provided arguments at [DebugLevel]. +// Spaces are added between arguments when neither is a string. func (s *SugaredLogger) Debug(args ...interface{}) { s.log(DebugLevel, "", args, nil) } -// Info uses fmt.Sprint to construct and log a message. +// Info logs the provided arguments at [InfoLevel]. +// Spaces are added between arguments when neither is a string. func (s *SugaredLogger) Info(args ...interface{}) { s.log(InfoLevel, "", args, nil) } -// Warn uses fmt.Sprint to construct and log a message. +// Warn logs the provided arguments at [WarnLevel]. +// Spaces are added between arguments when neither is a string. func (s *SugaredLogger) Warn(args ...interface{}) { s.log(WarnLevel, "", args, nil) } -// Error uses fmt.Sprint to construct and log a message. +// Error logs the provided arguments at [ErrorLevel]. +// Spaces are added between arguments when neither is a string. func (s *SugaredLogger) Error(args ...interface{}) { s.log(ErrorLevel, "", args, nil) } -// DPanic uses fmt.Sprint to construct and log a message. In development, the -// logger then panics. (See DPanicLevel for details.) +// DPanic logs the provided arguments at [DPanicLevel]. +// In development, the logger then panics. (See [DPanicLevel] for details.) +// Spaces are added between arguments when neither is a string. func (s *SugaredLogger) DPanic(args ...interface{}) { s.log(DPanicLevel, "", args, nil) } -// Panic uses fmt.Sprint to construct and log a message, then panics. +// Panic constructs a message with the provided arguments and panics. +// Spaces are added between arguments when neither is a string. func (s *SugaredLogger) Panic(args ...interface{}) { s.log(PanicLevel, "", args, nil) } -// Fatal uses fmt.Sprint to construct and log a message, then calls os.Exit. +// Fatal constructs a message with the provided arguments and calls os.Exit. +// Spaces are added between arguments when neither is a string. func (s *SugaredLogger) Fatal(args ...interface{}) { s.log(FatalLevel, "", args, nil) } -// Debugf uses fmt.Sprintf to log a templated message. +// Debugf formats the message according to the format specifier +// and logs it at [DebugLevel]. func (s *SugaredLogger) Debugf(template string, args ...interface{}) { s.log(DebugLevel, template, args, nil) } -// Infof uses fmt.Sprintf to log a templated message. +// Infof formats the message according to the format specifier +// and logs it at [InfoLevel]. func (s *SugaredLogger) Infof(template string, args ...interface{}) { s.log(InfoLevel, template, args, nil) } -// Warnf uses fmt.Sprintf to log a templated message. +// Warnf formats the message according to the format specifier +// and logs it at [WarnLevel]. func (s *SugaredLogger) Warnf(template string, args ...interface{}) { s.log(WarnLevel, template, args, nil) } -// Errorf uses fmt.Sprintf to log a templated message. +// Errorf formats the message according to the format specifier +// and logs it at [ErrorLevel]. func (s *SugaredLogger) Errorf(template string, args ...interface{}) { s.log(ErrorLevel, template, args, nil) } -// DPanicf uses fmt.Sprintf to log a templated message. In development, the -// logger then panics. (See DPanicLevel for details.) +// DPanicf formats the message according to the format specifier +// and logs it at [DPanicLevel]. +// In development, the logger then panics. (See [DPanicLevel] for details.) func (s *SugaredLogger) DPanicf(template string, args ...interface{}) { s.log(DPanicLevel, template, args, nil) } -// Panicf uses fmt.Sprintf to log a templated message, then panics. +// Panicf formats the message according to the format specifier +// and panics. func (s *SugaredLogger) Panicf(template string, args ...interface{}) { s.log(PanicLevel, template, args, nil) } -// Fatalf uses fmt.Sprintf to log a templated message, then calls os.Exit. +// Fatalf formats the message according to the format specifier +// and calls os.Exit. func (s *SugaredLogger) Fatalf(template string, args ...interface{}) { s.log(FatalLevel, template, args, nil) } @@ -168,7 +212,8 @@ func (s *SugaredLogger) Fatalf(template string, args ...interface{}) { // pairs are treated as they are in With. // // When debug-level logging is disabled, this is much faster than -// s.With(keysAndValues).Debug(msg) +// +// s.With(keysAndValues).Debug(msg) func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{}) { s.log(DebugLevel, msg, nil, keysAndValues) } @@ -210,11 +255,55 @@ func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) { s.log(FatalLevel, msg, nil, keysAndValues) } +// Debugln logs a message at [DebugLevel]. +// Spaces are always added between arguments. +func (s *SugaredLogger) Debugln(args ...interface{}) { + s.logln(DebugLevel, args, nil) +} + +// Infoln logs a message at [InfoLevel]. +// Spaces are always added between arguments. +func (s *SugaredLogger) Infoln(args ...interface{}) { + s.logln(InfoLevel, args, nil) +} + +// Warnln logs a message at [WarnLevel]. +// Spaces are always added between arguments. +func (s *SugaredLogger) Warnln(args ...interface{}) { + s.logln(WarnLevel, args, nil) +} + +// Errorln logs a message at [ErrorLevel]. +// Spaces are always added between arguments. +func (s *SugaredLogger) Errorln(args ...interface{}) { + s.logln(ErrorLevel, args, nil) +} + +// DPanicln logs a message at [DPanicLevel]. +// In development, the logger then panics. (See [DPanicLevel] for details.) +// Spaces are always added between arguments. +func (s *SugaredLogger) DPanicln(args ...interface{}) { + s.logln(DPanicLevel, args, nil) +} + +// Panicln logs a message at [PanicLevel] and panics. +// Spaces are always added between arguments. +func (s *SugaredLogger) Panicln(args ...interface{}) { + s.logln(PanicLevel, args, nil) +} + +// Fatalln logs a message at [FatalLevel] and calls os.Exit. +// Spaces are always added between arguments. +func (s *SugaredLogger) Fatalln(args ...interface{}) { + s.logln(FatalLevel, args, nil) +} + // Sync flushes any buffered log entries. func (s *SugaredLogger) Sync() error { return s.base.Sync() } +// log message with Sprint, Sprintf, or neither. func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interface{}, context []interface{}) { // If logging at this level is completely disabled, skip the overhead of // string formatting. @@ -228,6 +317,18 @@ func (s *SugaredLogger) log(lvl zapcore.Level, template string, fmtArgs []interf } } +// logln message with Sprintln +func (s *SugaredLogger) logln(lvl zapcore.Level, fmtArgs []interface{}, context []interface{}) { + if lvl < DPanicLevel && !s.base.Core().Enabled(lvl) { + return + } + + msg := getMessageln(fmtArgs) + if ce := s.base.Check(lvl, msg); ce != nil { + ce.Write(s.sweetenFields(context)...) + } +} + // getMessage format with Sprint, Sprintf, or neither. func getMessage(template string, fmtArgs []interface{}) string { if len(fmtArgs) == 0 { @@ -246,15 +347,24 @@ func getMessage(template string, fmtArgs []interface{}) string { return fmt.Sprint(fmtArgs...) } +// getMessageln format with Sprintln. +func getMessageln(fmtArgs []interface{}) string { + msg := fmt.Sprintln(fmtArgs...) + return msg[:len(msg)-1] +} + func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { if len(args) == 0 { return nil } - // Allocate enough space for the worst case; if users pass only structured - // fields, we shouldn't penalize them with extra allocations. - fields := make([]Field, 0, len(args)) - var invalid invalidPairs + var ( + // Allocate enough space for the worst case; if users pass only structured + // fields, we shouldn't penalize them with extra allocations. + fields = make([]Field, 0, len(args)) + invalid invalidPairs + seenError bool + ) for i := 0; i < len(args); { // This is a strongly-typed field. Consume it and move on. @@ -264,6 +374,18 @@ func (s *SugaredLogger) sweetenFields(args []interface{}) []Field { continue } + // If it is an error, consume it and move on. + if err, ok := args[i].(error); ok { + if !seenError { + seenError = true + fields = append(fields, Error(err)) + } else { + s.base.Error(_multipleErrMsg, Error(err)) + } + i++ + continue + } + // Make sure this element isn't a dangling key. if i == len(args)-1 { s.base.Error(_oddNumberErrMsg, Any("ignored", args[i])) diff --git a/vendor/go.uber.org/zap/writer.go b/vendor/go.uber.org/zap/writer.go index 86a709ab0be..06768c67919 100644 --- a/vendor/go.uber.org/zap/writer.go +++ b/vendor/go.uber.org/zap/writer.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2016-2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,6 @@ package zap import ( "fmt" "io" - "io/ioutil" "go.uber.org/zap/zapcore" @@ -49,40 +48,40 @@ import ( // os.Stdout and os.Stderr. When specified without a scheme, relative file // paths also work. func Open(paths ...string) (zapcore.WriteSyncer, func(), error) { - writers, close, err := open(paths) + writers, closeAll, err := open(paths) if err != nil { return nil, nil, err } writer := CombineWriteSyncers(writers...) - return writer, close, nil + return writer, closeAll, nil } func open(paths []string) ([]zapcore.WriteSyncer, func(), error) { writers := make([]zapcore.WriteSyncer, 0, len(paths)) closers := make([]io.Closer, 0, len(paths)) - close := func() { + closeAll := func() { for _, c := range closers { - c.Close() + _ = c.Close() } } var openErr error for _, path := range paths { - sink, err := newSink(path) + sink, err := _sinkRegistry.newSink(path) if err != nil { - openErr = multierr.Append(openErr, fmt.Errorf("couldn't open sink %q: %v", path, err)) + openErr = multierr.Append(openErr, fmt.Errorf("open sink %q: %w", path, err)) continue } writers = append(writers, sink) closers = append(closers, sink) } if openErr != nil { - close() - return writers, nil, openErr + closeAll() + return nil, nil, openErr } - return writers, close, nil + return writers, closeAll, nil } // CombineWriteSyncers is a utility that combines multiple WriteSyncers into a @@ -93,7 +92,7 @@ func open(paths []string) ([]zapcore.WriteSyncer, func(), error) { // using zapcore.NewMultiWriteSyncer and zapcore.Lock individually. func CombineWriteSyncers(writers ...zapcore.WriteSyncer) zapcore.WriteSyncer { if len(writers) == 0 { - return zapcore.AddSync(ioutil.Discard) + return zapcore.AddSync(io.Discard) } return zapcore.Lock(zapcore.NewMultiWriteSyncer(writers...)) } diff --git a/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go b/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go index ef2f7d9637b..a40e93b3ec8 100644 --- a/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go +++ b/vendor/go.uber.org/zap/zapcore/buffered_write_syncer.go @@ -43,6 +43,37 @@ const ( // // BufferedWriteSyncer is safe for concurrent use. You don't need to use // zapcore.Lock for WriteSyncers with BufferedWriteSyncer. +// +// To set up a BufferedWriteSyncer, construct a WriteSyncer for your log +// destination (*os.File is a valid WriteSyncer), wrap it with +// BufferedWriteSyncer, and defer a Stop() call for when you no longer need the +// object. +// +// func main() { +// ws := ... // your log destination +// bws := &zapcore.BufferedWriteSyncer{WS: ws} +// defer bws.Stop() +// +// // ... +// core := zapcore.NewCore(enc, bws, lvl) +// logger := zap.New(core) +// +// // ... +// } +// +// By default, a BufferedWriteSyncer will buffer up to 256 kilobytes of logs, +// waiting at most 30 seconds between flushes. +// You can customize these parameters by setting the Size or FlushInterval +// fields. +// For example, the following buffers up to 512 kB of logs before flushing them +// to Stderr, with a maximum of one minute between each flush. +// +// ws := &BufferedWriteSyncer{ +// WS: os.Stderr, +// Size: 512 * 1024, // 512 kB +// FlushInterval: time.Minute, +// } +// defer ws.Stop() type BufferedWriteSyncer struct { // WS is the WriteSyncer around which BufferedWriteSyncer will buffer // writes. diff --git a/vendor/go.uber.org/zap/zapcore/clock.go b/vendor/go.uber.org/zap/zapcore/clock.go index d2ea95b394b..422fd82a6b0 100644 --- a/vendor/go.uber.org/zap/zapcore/clock.go +++ b/vendor/go.uber.org/zap/zapcore/clock.go @@ -20,9 +20,7 @@ package zapcore -import ( - "time" -) +import "time" // DefaultClock is the default clock used by Zap in operations that require // time. This clock uses the system clock for all operations. diff --git a/vendor/go.uber.org/zap/zapcore/console_encoder.go b/vendor/go.uber.org/zap/zapcore/console_encoder.go index 2307af404c5..8ca0bfaf561 100644 --- a/vendor/go.uber.org/zap/zapcore/console_encoder.go +++ b/vendor/go.uber.org/zap/zapcore/console_encoder.go @@ -22,20 +22,20 @@ package zapcore import ( "fmt" - "sync" "go.uber.org/zap/buffer" "go.uber.org/zap/internal/bufferpool" + "go.uber.org/zap/internal/pool" ) -var _sliceEncoderPool = sync.Pool{ - New: func() interface{} { - return &sliceArrayEncoder{elems: make([]interface{}, 0, 2)} - }, -} +var _sliceEncoderPool = pool.New(func() *sliceArrayEncoder { + return &sliceArrayEncoder{ + elems: make([]interface{}, 0, 2), + } +}) func getSliceEncoder() *sliceArrayEncoder { - return _sliceEncoderPool.Get().(*sliceArrayEncoder) + return _sliceEncoderPool.Get() } func putSliceEncoder(e *sliceArrayEncoder) { @@ -125,11 +125,7 @@ func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, line.AppendString(ent.Stack) } - if c.LineEnding != "" { - line.AppendString(c.LineEnding) - } else { - line.AppendString(DefaultLineEnding) - } + line.AppendString(c.LineEnding) return line, nil } diff --git a/vendor/go.uber.org/zap/zapcore/core.go b/vendor/go.uber.org/zap/zapcore/core.go index a1ef8b034bb..776e93f6f35 100644 --- a/vendor/go.uber.org/zap/zapcore/core.go +++ b/vendor/go.uber.org/zap/zapcore/core.go @@ -69,6 +69,15 @@ type ioCore struct { out WriteSyncer } +var ( + _ Core = (*ioCore)(nil) + _ leveledEnabler = (*ioCore)(nil) +) + +func (c *ioCore) Level() Level { + return LevelOf(c.LevelEnabler) +} + func (c *ioCore) With(fields []Field) Core { clone := c.clone() addFields(clone.enc, fields) @@ -93,9 +102,9 @@ func (c *ioCore) Write(ent Entry, fields []Field) error { return err } if ent.Level > ErrorLevel { - // Since we may be crashing the program, sync the output. Ignore Sync - // errors, pending a clean solution to issue #370. - c.Sync() + // Since we may be crashing the program, sync the output. + // Ignore Sync errors, pending a clean solution to issue #370. + _ = c.Sync() } return nil } diff --git a/vendor/go.uber.org/zap/zapcore/encoder.go b/vendor/go.uber.org/zap/zapcore/encoder.go index 6601ca166c6..5769ff3e4e5 100644 --- a/vendor/go.uber.org/zap/zapcore/encoder.go +++ b/vendor/go.uber.org/zap/zapcore/encoder.go @@ -22,6 +22,7 @@ package zapcore import ( "encoding/json" + "io" "time" "go.uber.org/zap/buffer" @@ -187,10 +188,13 @@ func (e *TimeEncoder) UnmarshalText(text []byte) error { // UnmarshalYAML unmarshals YAML to a TimeEncoder. // If value is an object with a "layout" field, it will be unmarshaled to TimeEncoder with given layout. -// timeEncoder: -// layout: 06/01/02 03:04pm +// +// timeEncoder: +// layout: 06/01/02 03:04pm +// // If value is string, it uses UnmarshalText. -// timeEncoder: iso8601 +// +// timeEncoder: iso8601 func (e *TimeEncoder) UnmarshalYAML(unmarshal func(interface{}) error) error { var o struct { Layout string `json:"layout" yaml:"layout"` @@ -312,14 +316,15 @@ func (e *NameEncoder) UnmarshalText(text []byte) error { type EncoderConfig struct { // Set the keys used for each log entry. If any key is empty, that portion // of the entry is omitted. - MessageKey string `json:"messageKey" yaml:"messageKey"` - LevelKey string `json:"levelKey" yaml:"levelKey"` - TimeKey string `json:"timeKey" yaml:"timeKey"` - NameKey string `json:"nameKey" yaml:"nameKey"` - CallerKey string `json:"callerKey" yaml:"callerKey"` - FunctionKey string `json:"functionKey" yaml:"functionKey"` - StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"` - LineEnding string `json:"lineEnding" yaml:"lineEnding"` + MessageKey string `json:"messageKey" yaml:"messageKey"` + LevelKey string `json:"levelKey" yaml:"levelKey"` + TimeKey string `json:"timeKey" yaml:"timeKey"` + NameKey string `json:"nameKey" yaml:"nameKey"` + CallerKey string `json:"callerKey" yaml:"callerKey"` + FunctionKey string `json:"functionKey" yaml:"functionKey"` + StacktraceKey string `json:"stacktraceKey" yaml:"stacktraceKey"` + SkipLineEnding bool `json:"skipLineEnding" yaml:"skipLineEnding"` + LineEnding string `json:"lineEnding" yaml:"lineEnding"` // Configure the primitive representations of common complex types. For // example, some users may want all time.Times serialized as floating-point // seconds since epoch, while others may prefer ISO8601 strings. @@ -330,6 +335,9 @@ type EncoderConfig struct { // Unlike the other primitive type encoders, EncodeName is optional. The // zero value falls back to FullNameEncoder. EncodeName NameEncoder `json:"nameEncoder" yaml:"nameEncoder"` + // Configure the encoder for interface{} type objects. + // If not provided, objects are encoded using json.Encoder + NewReflectedEncoder func(io.Writer) ReflectedEncoder `json:"-" yaml:"-"` // Configures the field separator used by the console encoder. Defaults // to tab. ConsoleSeparator string `json:"consoleSeparator" yaml:"consoleSeparator"` diff --git a/vendor/go.uber.org/zap/zapcore/entry.go b/vendor/go.uber.org/zap/zapcore/entry.go index 0885505b75b..459a5d7ce3c 100644 --- a/vendor/go.uber.org/zap/zapcore/entry.go +++ b/vendor/go.uber.org/zap/zapcore/entry.go @@ -24,26 +24,23 @@ import ( "fmt" "runtime" "strings" - "sync" "time" + "go.uber.org/multierr" "go.uber.org/zap/internal/bufferpool" "go.uber.org/zap/internal/exit" - - "go.uber.org/multierr" + "go.uber.org/zap/internal/pool" ) -var ( - _cePool = sync.Pool{New: func() interface{} { - // Pre-allocate some space for cores. - return &CheckedEntry{ - cores: make([]Core, 4), - } - }} -) +var _cePool = pool.New(func() *CheckedEntry { + // Pre-allocate some space for cores. + return &CheckedEntry{ + cores: make([]Core, 4), + } +}) func getCheckedEntry() *CheckedEntry { - ce := _cePool.Get().(*CheckedEntry) + ce := _cePool.Get() ce.reset() return ce } @@ -152,6 +149,27 @@ type Entry struct { Stack string } +// CheckWriteHook is a custom action that may be executed after an entry is +// written. +// +// Register one on a CheckedEntry with the After method. +// +// if ce := logger.Check(...); ce != nil { +// ce = ce.After(hook) +// ce.Write(...) +// } +// +// You can configure the hook for Fatal log statements at the logger level with +// the zap.WithFatalHook option. +type CheckWriteHook interface { + // OnWrite is invoked with the CheckedEntry that was written and a list + // of fields added with that entry. + // + // The list of fields DOES NOT include fields that were already added + // to the logger with the With method. + OnWrite(*CheckedEntry, []Field) +} + // CheckWriteAction indicates what action to take after a log entry is // processed. Actions are ordered in increasing severity. type CheckWriteAction uint8 @@ -164,21 +182,36 @@ const ( WriteThenGoexit // WriteThenPanic causes a panic after Write. WriteThenPanic - // WriteThenFatal causes a fatal os.Exit after Write. + // WriteThenFatal causes an os.Exit(1) after Write. WriteThenFatal ) +// OnWrite implements the OnWrite method to keep CheckWriteAction compatible +// with the new CheckWriteHook interface which deprecates CheckWriteAction. +func (a CheckWriteAction) OnWrite(ce *CheckedEntry, _ []Field) { + switch a { + case WriteThenGoexit: + runtime.Goexit() + case WriteThenPanic: + panic(ce.Message) + case WriteThenFatal: + exit.With(1) + } +} + +var _ CheckWriteHook = CheckWriteAction(0) + // CheckedEntry is an Entry together with a collection of Cores that have // already agreed to log it. // -// CheckedEntry references should be created by calling AddCore or Should on a +// CheckedEntry references should be created by calling AddCore or After on a // nil *CheckedEntry. References are returned to a pool after Write, and MUST // NOT be retained after calling their Write method. type CheckedEntry struct { Entry ErrorOutput WriteSyncer dirty bool // best-effort detection of pool misuse - should CheckWriteAction + after CheckWriteHook cores []Core } @@ -186,7 +219,7 @@ func (ce *CheckedEntry) reset() { ce.Entry = Entry{} ce.ErrorOutput = nil ce.dirty = false - ce.should = WriteThenNoop + ce.after = nil for i := range ce.cores { // don't keep references to cores ce.cores[i] = nil @@ -209,7 +242,7 @@ func (ce *CheckedEntry) Write(fields ...Field) { // CheckedEntry is being used after it was returned to the pool, // the message may be an amalgamation from multiple call sites. fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", ce.Time, ce.Entry) - ce.ErrorOutput.Sync() + _ = ce.ErrorOutput.Sync() // ignore error } return } @@ -221,20 +254,14 @@ func (ce *CheckedEntry) Write(fields ...Field) { } if err != nil && ce.ErrorOutput != nil { fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", ce.Time, err) - ce.ErrorOutput.Sync() + _ = ce.ErrorOutput.Sync() // ignore error } - should, msg := ce.should, ce.Message - putCheckedEntry(ce) - - switch should { - case WriteThenPanic: - panic(msg) - case WriteThenFatal: - exit.Exit() - case WriteThenGoexit: - runtime.Goexit() + hook := ce.after + if hook != nil { + hook.OnWrite(ce, fields) } + putCheckedEntry(ce) } // AddCore adds a Core that has agreed to log this CheckedEntry. It's intended to be @@ -252,11 +279,20 @@ func (ce *CheckedEntry) AddCore(ent Entry, core Core) *CheckedEntry { // Should sets this CheckedEntry's CheckWriteAction, which controls whether a // Core will panic or fatal after writing this log entry. Like AddCore, it's // safe to call on nil CheckedEntry references. +// +// Deprecated: Use [CheckedEntry.After] instead. func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry { + return ce.After(ent, should) +} + +// After sets this CheckEntry's CheckWriteHook, which will be called after this +// log entry has been written. It's safe to call this on nil CheckedEntry +// references. +func (ce *CheckedEntry) After(ent Entry, hook CheckWriteHook) *CheckedEntry { if ce == nil { ce = getCheckedEntry() ce.Entry = ent } - ce.should = should + ce.after = hook return ce } diff --git a/vendor/go.uber.org/zap/zapcore/error.go b/vendor/go.uber.org/zap/zapcore/error.go index 74919b0ccb1..c40df13269a 100644 --- a/vendor/go.uber.org/zap/zapcore/error.go +++ b/vendor/go.uber.org/zap/zapcore/error.go @@ -23,7 +23,8 @@ package zapcore import ( "fmt" "reflect" - "sync" + + "go.uber.org/zap/internal/pool" ) // Encodes the given error into fields of an object. A field with the given @@ -36,13 +37,13 @@ import ( // causer (from github.com/pkg/errors), a ${key}Causes field is added with an // array of objects containing the errors this error was comprised of. // -// { -// "error": err.Error(), -// "errorVerbose": fmt.Sprintf("%+v", err), -// "errorCauses": [ -// ... -// ], -// } +// { +// "error": err.Error(), +// "errorVerbose": fmt.Sprintf("%+v", err), +// "errorCauses": [ +// ... +// ], +// } func encodeError(key string, err error, enc ObjectEncoder) (retErr error) { // Try to capture panics (from nil references or otherwise) when calling // the Error() method @@ -97,15 +98,18 @@ func (errs errArray) MarshalLogArray(arr ArrayEncoder) error { } el := newErrArrayElem(errs[i]) - arr.AppendObject(el) + err := arr.AppendObject(el) el.Free() + if err != nil { + return err + } } return nil } -var _errArrayElemPool = sync.Pool{New: func() interface{} { +var _errArrayElemPool = pool.New(func() *errArrayElem { return &errArrayElem{} -}} +}) // Encodes any error into a {"error": ...} re-using the same errors logic. // @@ -113,7 +117,7 @@ var _errArrayElemPool = sync.Pool{New: func() interface{} { type errArrayElem struct{ err error } func newErrArrayElem(err error) *errArrayElem { - e := _errArrayElemPool.Get().(*errArrayElem) + e := _errArrayElemPool.Get() e.err = err return e } diff --git a/vendor/go.uber.org/zap/zapcore/hook.go b/vendor/go.uber.org/zap/zapcore/hook.go index 5db4afb302b..198def9917c 100644 --- a/vendor/go.uber.org/zap/zapcore/hook.go +++ b/vendor/go.uber.org/zap/zapcore/hook.go @@ -27,6 +27,11 @@ type hooked struct { funcs []func(Entry) error } +var ( + _ Core = (*hooked)(nil) + _ leveledEnabler = (*hooked)(nil) +) + // RegisterHooks wraps a Core and runs a collection of user-defined callback // hooks each time a message is logged. Execution of the callbacks is blocking. // @@ -40,6 +45,10 @@ func RegisterHooks(core Core, hooks ...func(Entry) error) Core { } } +func (h *hooked) Level() Level { + return LevelOf(h.Core) +} + func (h *hooked) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { // Let the wrapped Core decide whether to log this message or not. This // also gives the downstream a chance to register itself directly with the diff --git a/vendor/go.uber.org/zap/zapcore/increase_level.go b/vendor/go.uber.org/zap/zapcore/increase_level.go index 5a1749261ab..7a11237ae97 100644 --- a/vendor/go.uber.org/zap/zapcore/increase_level.go +++ b/vendor/go.uber.org/zap/zapcore/increase_level.go @@ -27,6 +27,11 @@ type levelFilterCore struct { level LevelEnabler } +var ( + _ Core = (*levelFilterCore)(nil) + _ leveledEnabler = (*levelFilterCore)(nil) +) + // NewIncreaseLevelCore creates a core that can be used to increase the level of // an existing Core. It cannot be used to decrease the logging level, as it acts // as a filter before calling the underlying core. If level decreases the log level, @@ -45,6 +50,10 @@ func (c *levelFilterCore) Enabled(lvl Level) bool { return c.level.Enabled(lvl) } +func (c *levelFilterCore) Level() Level { + return LevelOf(c.level) +} + func (c *levelFilterCore) With(fields []Field) Core { return &levelFilterCore{c.core.With(fields), c.level} } diff --git a/vendor/go.uber.org/zap/zapcore/json_encoder.go b/vendor/go.uber.org/zap/zapcore/json_encoder.go index 5cf7d917e92..c8ab86979b0 100644 --- a/vendor/go.uber.org/zap/zapcore/json_encoder.go +++ b/vendor/go.uber.org/zap/zapcore/json_encoder.go @@ -22,26 +22,21 @@ package zapcore import ( "encoding/base64" - "encoding/json" "math" - "sync" "time" "unicode/utf8" "go.uber.org/zap/buffer" "go.uber.org/zap/internal/bufferpool" + "go.uber.org/zap/internal/pool" ) // For JSON-escaping; see jsonEncoder.safeAddString below. const _hex = "0123456789abcdef" -var _jsonPool = sync.Pool{New: func() interface{} { +var _jsonPool = pool.New(func() *jsonEncoder { return &jsonEncoder{} -}} - -func getJSONEncoder() *jsonEncoder { - return _jsonPool.Get().(*jsonEncoder) -} +}) func putJSONEncoder(enc *jsonEncoder) { if enc.reflectBuf != nil { @@ -64,7 +59,7 @@ type jsonEncoder struct { // for encoding generic values by reflection reflectBuf *buffer.Buffer - reflectEnc *json.Encoder + reflectEnc ReflectedEncoder } // NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder @@ -72,7 +67,9 @@ type jsonEncoder struct { // // Note that the encoder doesn't deduplicate keys, so it's possible to produce // a message like -// {"foo":"bar","foo":"baz"} +// +// {"foo":"bar","foo":"baz"} +// // This is permitted by the JSON specification, but not encouraged. Many // libraries will ignore duplicate key-value pairs (typically keeping the last // pair) when unmarshaling, but users should attempt to avoid adding duplicate @@ -82,6 +79,17 @@ func NewJSONEncoder(cfg EncoderConfig) Encoder { } func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder { + if cfg.SkipLineEnding { + cfg.LineEnding = "" + } else if cfg.LineEnding == "" { + cfg.LineEnding = DefaultLineEnding + } + + // If no EncoderConfig.NewReflectedEncoder is provided by the user, then use default + if cfg.NewReflectedEncoder == nil { + cfg.NewReflectedEncoder = defaultReflectedEncoder + } + return &jsonEncoder{ EncoderConfig: &cfg, buf: bufferpool.Get(), @@ -118,6 +126,11 @@ func (enc *jsonEncoder) AddComplex128(key string, val complex128) { enc.AppendComplex128(val) } +func (enc *jsonEncoder) AddComplex64(key string, val complex64) { + enc.addKey(key) + enc.AppendComplex64(val) +} + func (enc *jsonEncoder) AddDuration(key string, val time.Duration) { enc.addKey(key) enc.AppendDuration(val) @@ -128,6 +141,11 @@ func (enc *jsonEncoder) AddFloat64(key string, val float64) { enc.AppendFloat64(val) } +func (enc *jsonEncoder) AddFloat32(key string, val float32) { + enc.addKey(key) + enc.AppendFloat32(val) +} + func (enc *jsonEncoder) AddInt64(key string, val int64) { enc.addKey(key) enc.AppendInt64(val) @@ -136,10 +154,7 @@ func (enc *jsonEncoder) AddInt64(key string, val int64) { func (enc *jsonEncoder) resetReflectBuf() { if enc.reflectBuf == nil { enc.reflectBuf = bufferpool.Get() - enc.reflectEnc = json.NewEncoder(enc.reflectBuf) - - // For consistency with our custom JSON encoder. - enc.reflectEnc.SetEscapeHTML(false) + enc.reflectEnc = enc.NewReflectedEncoder(enc.reflectBuf) } else { enc.reflectBuf.Reset() } @@ -201,10 +216,16 @@ func (enc *jsonEncoder) AppendArray(arr ArrayMarshaler) error { } func (enc *jsonEncoder) AppendObject(obj ObjectMarshaler) error { + // Close ONLY new openNamespaces that are created during + // AppendObject(). + old := enc.openNamespaces + enc.openNamespaces = 0 enc.addElementSeparator() enc.buf.AppendByte('{') err := obj.MarshalLogObject(enc) enc.buf.AppendByte('}') + enc.closeOpenNamespaces() + enc.openNamespaces = old return err } @@ -220,16 +241,23 @@ func (enc *jsonEncoder) AppendByteString(val []byte) { enc.buf.AppendByte('"') } -func (enc *jsonEncoder) AppendComplex128(val complex128) { +// appendComplex appends the encoded form of the provided complex128 value. +// precision specifies the encoding precision for the real and imaginary +// components of the complex number. +func (enc *jsonEncoder) appendComplex(val complex128, precision int) { enc.addElementSeparator() // Cast to a platform-independent, fixed-size type. r, i := float64(real(val)), float64(imag(val)) enc.buf.AppendByte('"') // Because we're always in a quoted string, we can use strconv without // special-casing NaN and +/-Inf. - enc.buf.AppendFloat(r, 64) - enc.buf.AppendByte('+') - enc.buf.AppendFloat(i, 64) + enc.buf.AppendFloat(r, precision) + // If imaginary part is less than 0, minus (-) sign is added by default + // by AppendFloat. + if i >= 0 { + enc.buf.AppendByte('+') + } + enc.buf.AppendFloat(i, precision) enc.buf.AppendByte('i') enc.buf.AppendByte('"') } @@ -292,29 +320,28 @@ func (enc *jsonEncoder) AppendUint64(val uint64) { enc.buf.AppendUint(val) } -func (enc *jsonEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) } -func (enc *jsonEncoder) AddFloat32(k string, v float32) { enc.AddFloat64(k, float64(v)) } -func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } -func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } -func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } -func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } -func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } -func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } -func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } -func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } -func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } -func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) } -func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } -func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } -func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } -func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } -func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } -func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } -func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } -func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } -func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } -func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } -func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } +func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } +func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.appendComplex(complex128(v), 32) } +func (enc *jsonEncoder) AppendComplex128(v complex128) { enc.appendComplex(complex128(v), 64) } +func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } +func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } +func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } +func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } +func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } func (enc *jsonEncoder) Clone() Encoder { clone := enc.clone() @@ -323,7 +350,7 @@ func (enc *jsonEncoder) Clone() Encoder { } func (enc *jsonEncoder) clone() *jsonEncoder { - clone := getJSONEncoder() + clone := _jsonPool.Get() clone.EncoderConfig = enc.EncoderConfig clone.spaced = enc.spaced clone.openNamespaces = enc.openNamespaces @@ -335,7 +362,7 @@ func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, final := enc.clone() final.buf.AppendByte('{') - if final.LevelKey != "" { + if final.LevelKey != "" && final.EncodeLevel != nil { final.addKey(final.LevelKey) cur := final.buf.Len() final.EncodeLevel(ent.Level, final) @@ -396,11 +423,7 @@ func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, final.AddString(final.StacktraceKey, ent.Stack) } final.buf.AppendByte('}') - if final.LineEnding != "" { - final.buf.AppendString(final.LineEnding) - } else { - final.buf.AppendString(DefaultLineEnding) - } + final.buf.AppendString(final.LineEnding) ret := final.buf putJSONEncoder(final) @@ -415,6 +438,7 @@ func (enc *jsonEncoder) closeOpenNamespaces() { for i := 0; i < enc.openNamespaces; i++ { enc.buf.AppendByte('}') } + enc.openNamespaces = 0 } func (enc *jsonEncoder) addKey(key string) { @@ -462,73 +486,98 @@ func (enc *jsonEncoder) appendFloat(val float64, bitSize int) { // Unlike the standard library's encoder, it doesn't attempt to protect the // user from browser vulnerabilities or JSONP-related problems. func (enc *jsonEncoder) safeAddString(s string) { - for i := 0; i < len(s); { - if enc.tryAddRuneSelf(s[i]) { - i++ - continue - } - r, size := utf8.DecodeRuneInString(s[i:]) - if enc.tryAddRuneError(r, size) { - i++ - continue - } - enc.buf.AppendString(s[i : i+size]) - i += size - } + safeAppendStringLike( + (*buffer.Buffer).AppendString, + utf8.DecodeRuneInString, + enc.buf, + s, + ) } // safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte. func (enc *jsonEncoder) safeAddByteString(s []byte) { + safeAppendStringLike( + (*buffer.Buffer).AppendBytes, + utf8.DecodeRune, + enc.buf, + s, + ) +} + +// safeAppendStringLike is a generic implementation of safeAddString and safeAddByteString. +// It appends a string or byte slice to the buffer, escaping all special characters. +func safeAppendStringLike[S []byte | string]( + // appendTo appends this string-like object to the buffer. + appendTo func(*buffer.Buffer, S), + // decodeRune decodes the next rune from the string-like object + // and returns its value and width in bytes. + decodeRune func(S) (rune, int), + buf *buffer.Buffer, + s S, +) { + // The encoding logic below works by skipping over characters + // that can be safely copied as-is, + // until a character is found that needs special handling. + // At that point, we copy everything we've seen so far, + // and then handle that special character. + // + // last is the index of the last byte that was copied to the buffer. + last := 0 for i := 0; i < len(s); { - if enc.tryAddRuneSelf(s[i]) { + if s[i] >= utf8.RuneSelf { + // Character >= RuneSelf may be part of a multi-byte rune. + // They need to be decoded before we can decide how to handle them. + r, size := decodeRune(s[i:]) + if r != utf8.RuneError || size != 1 { + // No special handling required. + // Skip over this rune and continue. + i += size + continue + } + + // Invalid UTF-8 sequence. + // Replace it with the Unicode replacement character. + appendTo(buf, s[last:i]) + buf.AppendString(`\ufffd`) + i++ - continue - } - r, size := utf8.DecodeRune(s[i:]) - if enc.tryAddRuneError(r, size) { + last = i + } else { + // Character < RuneSelf is a single-byte UTF-8 rune. + if s[i] >= 0x20 && s[i] != '\\' && s[i] != '"' { + // No escaping necessary. + // Skip over this character and continue. + i++ + continue + } + + // This character needs to be escaped. + appendTo(buf, s[last:i]) + switch s[i] { + case '\\', '"': + buf.AppendByte('\\') + buf.AppendByte(s[i]) + case '\n': + buf.AppendByte('\\') + buf.AppendByte('n') + case '\r': + buf.AppendByte('\\') + buf.AppendByte('r') + case '\t': + buf.AppendByte('\\') + buf.AppendByte('t') + default: + // Encode bytes < 0x20, except for the escape sequences above. + buf.AppendString(`\u00`) + buf.AppendByte(_hex[s[i]>>4]) + buf.AppendByte(_hex[s[i]&0xF]) + } + i++ - continue + last = i } - enc.buf.Write(s[i : i+size]) - i += size - } -} - -// tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte. -func (enc *jsonEncoder) tryAddRuneSelf(b byte) bool { - if b >= utf8.RuneSelf { - return false } - if 0x20 <= b && b != '\\' && b != '"' { - enc.buf.AppendByte(b) - return true - } - switch b { - case '\\', '"': - enc.buf.AppendByte('\\') - enc.buf.AppendByte(b) - case '\n': - enc.buf.AppendByte('\\') - enc.buf.AppendByte('n') - case '\r': - enc.buf.AppendByte('\\') - enc.buf.AppendByte('r') - case '\t': - enc.buf.AppendByte('\\') - enc.buf.AppendByte('t') - default: - // Encode bytes < 0x20, except for the escape sequences above. - enc.buf.AppendString(`\u00`) - enc.buf.AppendByte(_hex[b>>4]) - enc.buf.AppendByte(_hex[b&0xF]) - } - return true -} -func (enc *jsonEncoder) tryAddRuneError(r rune, size int) bool { - if r == utf8.RuneError && size == 1 { - enc.buf.AppendString(`\ufffd`) - return true - } - return false + // add remaining + appendTo(buf, s[last:]) } diff --git a/vendor/go.uber.org/atomic/bool_ext.go b/vendor/go.uber.org/zap/zapcore/lazy_with.go similarity index 60% rename from vendor/go.uber.org/atomic/bool_ext.go rename to vendor/go.uber.org/zap/zapcore/lazy_with.go index c7bf7a827a8..05288d6a88e 100644 --- a/vendor/go.uber.org/atomic/bool_ext.go +++ b/vendor/go.uber.org/zap/zapcore/lazy_with.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Uber Technologies, Inc. +// Copyright (c) 2023 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,36 +18,37 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -package atomic +package zapcore -import ( - "strconv" -) +import "sync" -//go:generate bin/gen-atomicwrapper -name=Bool -type=bool -wrapped=Uint32 -pack=boolToInt -unpack=truthy -cas -swap -json -file=bool.go - -func truthy(n uint32) bool { - return n == 1 +type lazyWithCore struct { + Core + sync.Once + fields []Field } -func boolToInt(b bool) uint32 { - if b { - return 1 +// NewLazyWith wraps a Core with a "lazy" Core that will only encode fields if +// the logger is written to (or is further chained in a lon-lazy manner). +func NewLazyWith(core Core, fields []Field) Core { + return &lazyWithCore{ + Core: core, + fields: fields, } - return 0 } -// Toggle atomically negates the Boolean and returns the previous value. -func (b *Bool) Toggle() bool { - for { - old := b.Load() - if b.CAS(old, !old) { - return old - } - } +func (d *lazyWithCore) initOnce() { + d.Once.Do(func() { + d.Core = d.Core.With(d.fields) + }) +} + +func (d *lazyWithCore) With(fields []Field) Core { + d.initOnce() + return d.Core.With(fields) } -// String encodes the wrapped value as a string. -func (b *Bool) String() string { - return strconv.FormatBool(b.Load()) +func (d *lazyWithCore) Check(e Entry, ce *CheckedEntry) *CheckedEntry { + d.initOnce() + return d.Core.Check(e, ce) } diff --git a/vendor/go.uber.org/zap/zapcore/level.go b/vendor/go.uber.org/zap/zapcore/level.go index e575c9f432c..e01a2413166 100644 --- a/vendor/go.uber.org/zap/zapcore/level.go +++ b/vendor/go.uber.org/zap/zapcore/level.go @@ -53,8 +53,62 @@ const ( _minLevel = DebugLevel _maxLevel = FatalLevel + + // InvalidLevel is an invalid value for Level. + // + // Core implementations may panic if they see messages of this level. + InvalidLevel = _maxLevel + 1 ) +// ParseLevel parses a level based on the lower-case or all-caps ASCII +// representation of the log level. If the provided ASCII representation is +// invalid an error is returned. +// +// This is particularly useful when dealing with text input to configure log +// levels. +func ParseLevel(text string) (Level, error) { + var level Level + err := level.UnmarshalText([]byte(text)) + return level, err +} + +type leveledEnabler interface { + LevelEnabler + + Level() Level +} + +// LevelOf reports the minimum enabled log level for the given LevelEnabler +// from Zap's supported log levels, or [InvalidLevel] if none of them are +// enabled. +// +// A LevelEnabler may implement a 'Level() Level' method to override the +// behavior of this function. +// +// func (c *core) Level() Level { +// return c.currentLevel +// } +// +// It is recommended that [Core] implementations that wrap other cores use +// LevelOf to retrieve the level of the wrapped core. For example, +// +// func (c *coreWrapper) Level() Level { +// return zapcore.LevelOf(c.wrappedCore) +// } +func LevelOf(enab LevelEnabler) Level { + if lvler, ok := enab.(leveledEnabler); ok { + return lvler.Level() + } + + for lvl := _minLevel; lvl <= _maxLevel; lvl++ { + if enab.Enabled(lvl) { + return lvl + } + } + + return InvalidLevel +} + // String returns a lower-case ASCII representation of the log level. func (l Level) String() string { switch l { diff --git a/vendor/go.uber.org/zap/global_go112.go b/vendor/go.uber.org/zap/zapcore/reflected_encoder.go similarity index 64% rename from vendor/go.uber.org/zap/global_go112.go rename to vendor/go.uber.org/zap/zapcore/reflected_encoder.go index 6b5dbda8076..8746360eca6 100644 --- a/vendor/go.uber.org/zap/global_go112.go +++ b/vendor/go.uber.org/zap/zapcore/reflected_encoder.go @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Uber Technologies, Inc. +// Copyright (c) 2016 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -18,9 +18,24 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -// See #682 for more information. -// +build go1.12 +package zapcore -package zap +import ( + "encoding/json" + "io" +) -const _stdLogDefaultDepth = 1 +// ReflectedEncoder serializes log fields that can't be serialized with Zap's +// JSON encoder. These have the ReflectType field type. +// Use EncoderConfig.NewReflectedEncoder to set this. +type ReflectedEncoder interface { + // Encode encodes and writes to the underlying data stream. + Encode(interface{}) error +} + +func defaultReflectedEncoder(w io.Writer) ReflectedEncoder { + enc := json.NewEncoder(w) + // For consistency with our custom JSON encoder. + enc.SetEscapeHTML(false) + return enc +} diff --git a/vendor/go.uber.org/zap/zapcore/sampler.go b/vendor/go.uber.org/zap/zapcore/sampler.go index 31ed96e129f..b7c093a4f2d 100644 --- a/vendor/go.uber.org/zap/zapcore/sampler.go +++ b/vendor/go.uber.org/zap/zapcore/sampler.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2016-2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,8 @@ package zapcore import ( + "sync/atomic" "time" - - "go.uber.org/atomic" ) const ( @@ -66,16 +65,16 @@ func (c *counter) IncCheckReset(t time.Time, tick time.Duration) uint64 { tn := t.UnixNano() resetAfter := c.resetAt.Load() if resetAfter > tn { - return c.counter.Inc() + return c.counter.Add(1) } c.counter.Store(1) newResetAfter := tn + tick.Nanoseconds() - if !c.resetAt.CAS(resetAfter, newResetAfter) { + if !c.resetAt.CompareAndSwap(resetAfter, newResetAfter) { // We raced with another goroutine trying to reset, and it also reset // the counter to 1, so we need to reincrement the counter. - return c.counter.Inc() + return c.counter.Add(1) } return 1 @@ -113,12 +112,12 @@ func nopSamplingHook(Entry, SamplingDecision) {} // This hook may be used to get visibility into the performance of the sampler. // For example, use it to track metrics of dropped versus sampled logs. // -// var dropped atomic.Int64 -// zapcore.SamplerHook(func(ent zapcore.Entry, dec zapcore.SamplingDecision) { -// if dec&zapcore.LogDropped > 0 { -// dropped.Inc() -// } -// }) +// var dropped atomic.Int64 +// zapcore.SamplerHook(func(ent zapcore.Entry, dec zapcore.SamplingDecision) { +// if dec&zapcore.LogDropped > 0 { +// dropped.Inc() +// } +// }) func SamplerHook(hook func(entry Entry, dec SamplingDecision)) SamplerOption { return optionFunc(func(s *sampler) { s.hook = hook @@ -133,10 +132,21 @@ func SamplerHook(hook func(entry Entry, dec SamplingDecision)) SamplerOption { // each tick. If more Entries with the same level and message are seen during // the same interval, every Mth message is logged and the rest are dropped. // +// For example, +// +// core = NewSamplerWithOptions(core, time.Second, 10, 5) +// +// This will log the first 10 log entries with the same level and message +// in a one second interval as-is. Following that, it will allow through +// every 5th log entry with the same level and message in that interval. +// +// If thereafter is zero, the Core will drop all log entries after the first N +// in that interval. +// // Sampler can be configured to report sampling decisions with the SamplerHook // option. // -// Keep in mind that zap's sampling implementation is optimized for speed over +// Keep in mind that Zap's sampling implementation is optimized for speed over // absolute precision; under load, each tick may be slightly over- or // under-sampled. func NewSamplerWithOptions(core Core, tick time.Duration, first, thereafter int, opts ...SamplerOption) Core { @@ -164,6 +174,11 @@ type sampler struct { hook func(Entry, SamplingDecision) } +var ( + _ Core = (*sampler)(nil) + _ leveledEnabler = (*sampler)(nil) +) + // NewSampler creates a Core that samples incoming entries, which // caps the CPU and I/O load of logging while attempting to preserve a // representative subset of your logs. @@ -181,6 +196,10 @@ func NewSampler(core Core, tick time.Duration, first, thereafter int) Core { return NewSamplerWithOptions(core, tick, first, thereafter) } +func (s *sampler) Level() Level { + return LevelOf(s.Core) +} + func (s *sampler) With(fields []Field) Core { return &sampler{ Core: s.Core.With(fields), @@ -200,7 +219,7 @@ func (s *sampler) Check(ent Entry, ce *CheckedEntry) *CheckedEntry { if ent.Level >= _minLevel && ent.Level <= _maxLevel { counter := s.counts.get(ent.Level, ent.Message) n := counter.IncCheckReset(ent.Time, s.tick) - if n > s.first && (n-s.first)%s.thereafter != 0 { + if n > s.first && (s.thereafter == 0 || (n-s.first)%s.thereafter != 0) { s.hook(ent, LogDropped) return ce } diff --git a/vendor/go.uber.org/zap/zapcore/tee.go b/vendor/go.uber.org/zap/zapcore/tee.go index 07a32eef9a4..9bb32f05576 100644 --- a/vendor/go.uber.org/zap/zapcore/tee.go +++ b/vendor/go.uber.org/zap/zapcore/tee.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2016-2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -24,6 +24,11 @@ import "go.uber.org/multierr" type multiCore []Core +var ( + _ leveledEnabler = multiCore(nil) + _ Core = multiCore(nil) +) + // NewTee creates a Core that duplicates log entries into two or more // underlying Cores. // @@ -48,6 +53,16 @@ func (mc multiCore) With(fields []Field) Core { return clone } +func (mc multiCore) Level() Level { + minLvl := _maxLevel // mc is never empty + for i := range mc { + if lvl := LevelOf(mc[i]); lvl < minLvl { + minLvl = lvl + } + } + return minLvl +} + func (mc multiCore) Enabled(lvl Level) bool { for i := range mc { if mc[i].Enabled(lvl) { diff --git a/vendor/go.uber.org/zap/zapgrpc/zapgrpc.go b/vendor/go.uber.org/zap/zapgrpc/zapgrpc.go index 356e12741e0..6823773b727 100644 --- a/vendor/go.uber.org/zap/zapgrpc/zapgrpc.go +++ b/vendor/go.uber.org/zap/zapgrpc/zapgrpc.go @@ -30,10 +30,10 @@ import ( // See https://github.com/grpc/grpc-go/blob/v1.35.0/grpclog/loggerv2.go#L77-L86 const ( - grpcLvlInfo = 0 - grpcLvlWarn = 1 - grpcLvlError = 2 - grpcLvlFatal = 3 + grpcLvlInfo int = iota + grpcLvlWarn + grpcLvlError + grpcLvlFatal ) var ( @@ -61,6 +61,7 @@ func (f optionFunc) apply(log *Logger) { // WithDebug configures a Logger to print at zap's DebugLevel instead of // InfoLevel. // It only affects the Printf, Println and Print methods, which are only used in the gRPC v1 grpclog.Logger API. +// // Deprecated: use grpclog.SetLoggerV2() for v2 API. func WithDebug() Option { return optionFunc(func(logger *Logger) { @@ -146,19 +147,22 @@ type Logger struct { } // Print implements grpclog.Logger. -// Deprecated: use Info(). +// +// Deprecated: use [Logger.Info]. func (l *Logger) Print(args ...interface{}) { l.print.Print(args...) } // Printf implements grpclog.Logger. -// Deprecated: use Infof(). +// +// Deprecated: use [Logger.Infof]. func (l *Logger) Printf(format string, args ...interface{}) { l.print.Printf(format, args...) } // Println implements grpclog.Logger. -// Deprecated: use Info(). +// +// Deprecated: use [Logger.Info]. func (l *Logger) Println(args ...interface{}) { l.print.Println(args...) } diff --git a/vendor/go.uber.org/zap/zaptest/observer/observer.go b/vendor/go.uber.org/zap/zaptest/observer/observer.go index 03866bd91b2..f77f1308baf 100644 --- a/vendor/go.uber.org/zap/zaptest/observer/observer.go +++ b/vendor/go.uber.org/zap/zaptest/observer/observer.go @@ -1,4 +1,4 @@ -// Copyright (c) 2016 Uber Technologies, Inc. +// Copyright (c) 2016-2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -29,6 +29,7 @@ import ( "sync" "time" + "go.uber.org/zap/internal" "go.uber.org/zap/zapcore" ) @@ -50,9 +51,7 @@ func (o *ObservedLogs) Len() int { func (o *ObservedLogs) All() []LoggedEntry { o.mu.RLock() ret := make([]LoggedEntry, len(o.logs)) - for i := range o.logs { - ret[i] = o.logs[i] - } + copy(ret, o.logs) o.mu.RUnlock() return ret } @@ -160,6 +159,15 @@ type contextObserver struct { context []zapcore.Field } +var ( + _ zapcore.Core = (*contextObserver)(nil) + _ internal.LeveledEnabler = (*contextObserver)(nil) +) + +func (co *contextObserver) Level() zapcore.Level { + return zapcore.LevelOf(co.LevelEnabler) +} + func (co *contextObserver) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { if co.Enabled(ent.Level) { return ce.AddCore(ent, co) diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b.go b/vendor/golang.org/x/crypto/blake2b/blake2b.go new file mode 100644 index 00000000000..d2e98d4295b --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b.go @@ -0,0 +1,291 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 +// and the extendable output function (XOF) BLAKE2Xb. +// +// BLAKE2b is optimized for 64-bit platforms—including NEON-enabled ARMs—and +// produces digests of any size between 1 and 64 bytes. +// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf +// and for BLAKE2Xb see https://blake2.net/blake2x.pdf +// +// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512). +// If you need a secret-key MAC (message authentication code), use the New512 +// function with a non-nil key. +// +// BLAKE2X is a construction to compute hash values larger than 64 bytes. It +// can produce hash values between 0 and 4 GiB. +package blake2b + +import ( + "encoding/binary" + "errors" + "hash" +) + +const ( + // The blocksize of BLAKE2b in bytes. + BlockSize = 128 + // The hash size of BLAKE2b-512 in bytes. + Size = 64 + // The hash size of BLAKE2b-384 in bytes. + Size384 = 48 + // The hash size of BLAKE2b-256 in bytes. + Size256 = 32 +) + +var ( + useAVX2 bool + useAVX bool + useSSE4 bool +) + +var ( + errKeySize = errors.New("blake2b: invalid key size") + errHashSize = errors.New("blake2b: invalid hash size") +) + +var iv = [8]uint64{ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +} + +// Sum512 returns the BLAKE2b-512 checksum of the data. +func Sum512(data []byte) [Size]byte { + var sum [Size]byte + checkSum(&sum, Size, data) + return sum +} + +// Sum384 returns the BLAKE2b-384 checksum of the data. +func Sum384(data []byte) [Size384]byte { + var sum [Size]byte + var sum384 [Size384]byte + checkSum(&sum, Size384, data) + copy(sum384[:], sum[:Size384]) + return sum384 +} + +// Sum256 returns the BLAKE2b-256 checksum of the data. +func Sum256(data []byte) [Size256]byte { + var sum [Size]byte + var sum256 [Size256]byte + checkSum(&sum, Size256, data) + copy(sum256[:], sum[:Size256]) + return sum256 +} + +// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil +// key turns the hash into a MAC. The key must be between zero and 64 bytes long. +func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) } + +// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil +// key turns the hash into a MAC. The key must be between zero and 64 bytes long. +func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) } + +// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil +// key turns the hash into a MAC. The key must be between zero and 64 bytes long. +func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) } + +// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length. +// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long. +// The hash size can be a value between 1 and 64 but it is highly recommended to use +// values equal or greater than: +// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). +// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long). +// When the key is nil, the returned hash.Hash implements BinaryMarshaler +// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. +func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) } + +func newDigest(hashSize int, key []byte) (*digest, error) { + if hashSize < 1 || hashSize > Size { + return nil, errHashSize + } + if len(key) > Size { + return nil, errKeySize + } + d := &digest{ + size: hashSize, + keyLen: len(key), + } + copy(d.key[:], key) + d.Reset() + return d, nil +} + +func checkSum(sum *[Size]byte, hashSize int, data []byte) { + h := iv + h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24) + var c [2]uint64 + + if length := len(data); length > BlockSize { + n := length &^ (BlockSize - 1) + if length == n { + n -= BlockSize + } + hashBlocks(&h, &c, 0, data[:n]) + data = data[n:] + } + + var block [BlockSize]byte + offset := copy(block[:], data) + remaining := uint64(BlockSize - offset) + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) + + for i, v := range h[:(hashSize+7)/8] { + binary.LittleEndian.PutUint64(sum[8*i:], v) + } +} + +type digest struct { + h [8]uint64 + c [2]uint64 + size int + block [BlockSize]byte + offset int + + key [BlockSize]byte + keyLen int +} + +const ( + magic = "b2b" + marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1 +) + +func (d *digest) MarshalBinary() ([]byte, error) { + if d.keyLen != 0 { + return nil, errors.New("crypto/blake2b: cannot marshal MACs") + } + b := make([]byte, 0, marshaledSize) + b = append(b, magic...) + for i := 0; i < 8; i++ { + b = appendUint64(b, d.h[i]) + } + b = appendUint64(b, d.c[0]) + b = appendUint64(b, d.c[1]) + // Maximum value for size is 64 + b = append(b, byte(d.size)) + b = append(b, d.block[:]...) + b = append(b, byte(d.offset)) + return b, nil +} + +func (d *digest) UnmarshalBinary(b []byte) error { + if len(b) < len(magic) || string(b[:len(magic)]) != magic { + return errors.New("crypto/blake2b: invalid hash state identifier") + } + if len(b) != marshaledSize { + return errors.New("crypto/blake2b: invalid hash state size") + } + b = b[len(magic):] + for i := 0; i < 8; i++ { + b, d.h[i] = consumeUint64(b) + } + b, d.c[0] = consumeUint64(b) + b, d.c[1] = consumeUint64(b) + d.size = int(b[0]) + b = b[1:] + copy(d.block[:], b[:BlockSize]) + b = b[BlockSize:] + d.offset = int(b[0]) + return nil +} + +func (d *digest) BlockSize() int { return BlockSize } + +func (d *digest) Size() int { return d.size } + +func (d *digest) Reset() { + d.h = iv + d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24) + d.offset, d.c[0], d.c[1] = 0, 0, 0 + if d.keyLen > 0 { + d.block = d.key + d.offset = BlockSize + } +} + +func (d *digest) Write(p []byte) (n int, err error) { + n = len(p) + + if d.offset > 0 { + remaining := BlockSize - d.offset + if n <= remaining { + d.offset += copy(d.block[d.offset:], p) + return + } + copy(d.block[d.offset:], p[:remaining]) + hashBlocks(&d.h, &d.c, 0, d.block[:]) + d.offset = 0 + p = p[remaining:] + } + + if length := len(p); length > BlockSize { + nn := length &^ (BlockSize - 1) + if length == nn { + nn -= BlockSize + } + hashBlocks(&d.h, &d.c, 0, p[:nn]) + p = p[nn:] + } + + if len(p) > 0 { + d.offset += copy(d.block[:], p) + } + + return +} + +func (d *digest) Sum(sum []byte) []byte { + var hash [Size]byte + d.finalize(&hash) + return append(sum, hash[:d.size]...) +} + +func (d *digest) finalize(hash *[Size]byte) { + var block [BlockSize]byte + copy(block[:], d.block[:d.offset]) + remaining := uint64(BlockSize - d.offset) + + c := d.c + if c[0] < remaining { + c[1]-- + } + c[0] -= remaining + + h := d.h + hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) + + for i, v := range h { + binary.LittleEndian.PutUint64(hash[8*i:], v) + } +} + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + binary.BigEndian.PutUint64(a[:], x) + return append(b, a[:]...) +} + +func appendUint32(b []byte, x uint32) []byte { + var a [4]byte + binary.BigEndian.PutUint32(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + x := binary.BigEndian.Uint64(b) + return b[8:], x +} + +func consumeUint32(b []byte) ([]byte, uint32) { + x := binary.BigEndian.Uint32(b) + return b[4:], x +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go new file mode 100644 index 00000000000..199c21d27aa --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.go @@ -0,0 +1,37 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && gc && !purego + +package blake2b + +import "golang.org/x/sys/cpu" + +func init() { + useAVX2 = cpu.X86.HasAVX2 + useAVX = cpu.X86.HasAVX + useSSE4 = cpu.X86.HasSSE41 +} + +//go:noescape +func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +//go:noescape +func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +//go:noescape +func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + switch { + case useAVX2: + hashBlocksAVX2(h, c, flag, blocks) + case useAVX: + hashBlocksAVX(h, c, flag, blocks) + case useSSE4: + hashBlocksSSE4(h, c, flag, blocks) + default: + hashBlocksGeneric(h, c, flag, blocks) + } +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s new file mode 100644 index 00000000000..9ae8206c201 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s @@ -0,0 +1,744 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && gc && !purego + +#include "textflag.h" + +DATA ·AVX2_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX2_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +DATA ·AVX2_iv0<>+0x10(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX2_iv0<>+0x18(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX2_iv0<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_iv1<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·AVX2_iv1<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +DATA ·AVX2_iv1<>+0x10(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX2_iv1<>+0x18(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX2_iv1<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +DATA ·AVX2_c40<>+0x10(SB)/8, $0x0201000706050403 +DATA ·AVX2_c40<>+0x18(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX2_c40<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX2_c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +DATA ·AVX2_c48<>+0x10(SB)/8, $0x0100070605040302 +DATA ·AVX2_c48<>+0x18(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX2_c48<>(SB), (NOPTR+RODATA), $32 + +DATA ·AVX_iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·AVX_iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +GLOBL ·AVX_iv0<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b +DATA ·AVX_iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·AVX_iv1<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv2<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·AVX_iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·AVX_iv2<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b +DATA ·AVX_iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 +GLOBL ·AVX_iv3<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·AVX_c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·AVX_c40<>(SB), (NOPTR+RODATA), $16 + +DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16 + +#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39 +#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93 +#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e +#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93 +#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39 + +#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \ + VPADDQ m0, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFD $-79, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPSHUFB c40, Y1, Y1; \ + VPADDQ m1, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFB c48, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPADDQ Y1, Y1, t; \ + VPSRLQ $63, Y1, Y1; \ + VPXOR t, Y1, Y1; \ + VPERMQ_0x39_Y1_Y1; \ + VPERMQ_0x4E_Y2_Y2; \ + VPERMQ_0x93_Y3_Y3; \ + VPADDQ m2, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFD $-79, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPSHUFB c40, Y1, Y1; \ + VPADDQ m3, Y0, Y0; \ + VPADDQ Y1, Y0, Y0; \ + VPXOR Y0, Y3, Y3; \ + VPSHUFB c48, Y3, Y3; \ + VPADDQ Y3, Y2, Y2; \ + VPXOR Y2, Y1, Y1; \ + VPADDQ Y1, Y1, t; \ + VPSRLQ $63, Y1, Y1; \ + VPXOR t, Y1, Y1; \ + VPERMQ_0x39_Y3_Y3; \ + VPERMQ_0x4E_Y2_Y2; \ + VPERMQ_0x93_Y1_Y1 + +#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E +#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26 +#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E +#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36 +#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E + +#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n +#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n +#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n +#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n +#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n + +#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01 +#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01 +#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01 +#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01 +#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01 + +#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01 +#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01 + +#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8 +#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01 + +// load msg: Y12 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \ + VMOVQ_SI_X12(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X12(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y12, Y12 + +// load msg: Y13 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \ + VMOVQ_SI_X13(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X13(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y13, Y13 + +// load msg: Y14 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \ + VMOVQ_SI_X14(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X14(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y14, Y14 + +// load msg: Y15 = (i0, i1, i2, i3) +// i0, i1, i2, i3 must not be 0 +#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \ + VMOVQ_SI_X15(i0*8); \ + VMOVQ_SI_X11(i2*8); \ + VPINSRQ_1_SI_X15(i1*8); \ + VPINSRQ_1_SI_X11(i3*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \ + VMOVQ_SI_X12_0; \ + VMOVQ_SI_X11(4*8); \ + VPINSRQ_1_SI_X12(2*8); \ + VPINSRQ_1_SI_X11(6*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \ + LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \ + LOAD_MSG_AVX2_Y15(9, 11, 13, 15) + +#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \ + LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \ + LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \ + VMOVQ_SI_X11(11*8); \ + VPSHUFD $0x4E, 0*8(SI), X14; \ + VPINSRQ_1_SI_X11(5*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + LOAD_MSG_AVX2_Y15(12, 2, 7, 3) + +#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \ + VMOVQ_SI_X11(5*8); \ + VMOVDQU 11*8(SI), X12; \ + VPINSRQ_1_SI_X11(15*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + VMOVQ_SI_X13(8*8); \ + VMOVQ_SI_X11(2*8); \ + VPINSRQ_1_SI_X13_0; \ + VPINSRQ_1_SI_X11(13*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \ + LOAD_MSG_AVX2_Y15(14, 6, 1, 4) + +#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \ + LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \ + LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \ + LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \ + VMOVQ_SI_X15(6*8); \ + VMOVQ_SI_X11_0; \ + VPINSRQ_1_SI_X15(10*8); \ + VPINSRQ_1_SI_X11(8*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \ + LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \ + VMOVQ_SI_X13_0; \ + VMOVQ_SI_X11(4*8); \ + VPINSRQ_1_SI_X13(7*8); \ + VPINSRQ_1_SI_X11(15*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \ + LOAD_MSG_AVX2_Y15(1, 12, 8, 13) + +#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X11_0; \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X11(8*8); \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \ + LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \ + LOAD_MSG_AVX2_Y15(13, 5, 14, 9) + +#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \ + LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \ + LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \ + VMOVQ_SI_X14_0; \ + VPSHUFD $0x4E, 8*8(SI), X11; \ + VPINSRQ_1_SI_X14(6*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + LOAD_MSG_AVX2_Y15(7, 3, 2, 11) + +#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \ + LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \ + LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \ + LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \ + VMOVQ_SI_X15_0; \ + VMOVQ_SI_X11(6*8); \ + VPINSRQ_1_SI_X15(4*8); \ + VPINSRQ_1_SI_X11(10*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \ + VMOVQ_SI_X12(6*8); \ + VMOVQ_SI_X11(11*8); \ + VPINSRQ_1_SI_X12(14*8); \ + VPINSRQ_1_SI_X11_0; \ + VINSERTI128 $1, X11, Y12, Y12; \ + LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \ + VMOVQ_SI_X11(1*8); \ + VMOVDQU 12*8(SI), X14; \ + VPINSRQ_1_SI_X11(10*8); \ + VINSERTI128 $1, X11, Y14, Y14; \ + VMOVQ_SI_X15(2*8); \ + VMOVDQU 4*8(SI), X11; \ + VPINSRQ_1_SI_X15(7*8); \ + VINSERTI128 $1, X11, Y15, Y15 + +#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \ + LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \ + VMOVQ_SI_X13(2*8); \ + VPSHUFD $0x4E, 5*8(SI), X11; \ + VPINSRQ_1_SI_X13(4*8); \ + VINSERTI128 $1, X11, Y13, Y13; \ + LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \ + VMOVQ_SI_X15(11*8); \ + VMOVQ_SI_X11(12*8); \ + VPINSRQ_1_SI_X15(14*8); \ + VPINSRQ_1_SI_X11_0; \ + VINSERTI128 $1, X11, Y15, Y15 + +// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksAVX2(SB), 4, $320-48 // frame size = 288 + 32 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, DX + ADDQ $31, DX + ANDQ $~31, DX + + MOVQ CX, 16(DX) + XORQ CX, CX + MOVQ CX, 24(DX) + + VMOVDQU ·AVX2_c40<>(SB), Y4 + VMOVDQU ·AVX2_c48<>(SB), Y5 + + VMOVDQU 0(AX), Y8 + VMOVDQU 32(AX), Y9 + VMOVDQU ·AVX2_iv0<>(SB), Y6 + VMOVDQU ·AVX2_iv1<>(SB), Y7 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + MOVQ R9, 8(DX) + +loop: + ADDQ $128, R8 + MOVQ R8, 0(DX) + CMPQ R8, $128 + JGE noinc + INCQ R9 + MOVQ R9, 8(DX) + +noinc: + VMOVDQA Y8, Y0 + VMOVDQA Y9, Y1 + VMOVDQA Y6, Y2 + VPXOR 0(DX), Y7, Y3 + + LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() + VMOVDQA Y12, 32(DX) + VMOVDQA Y13, 64(DX) + VMOVDQA Y14, 96(DX) + VMOVDQA Y15, 128(DX) + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() + VMOVDQA Y12, 160(DX) + VMOVDQA Y13, 192(DX) + VMOVDQA Y14, 224(DX) + VMOVDQA Y15, 256(DX) + + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() + ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5) + + ROUND_AVX2(32(DX), 64(DX), 96(DX), 128(DX), Y10, Y4, Y5) + ROUND_AVX2(160(DX), 192(DX), 224(DX), 256(DX), Y10, Y4, Y5) + + VPXOR Y0, Y8, Y8 + VPXOR Y1, Y9, Y9 + VPXOR Y2, Y8, Y8 + VPXOR Y3, Y9, Y9 + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + + VMOVDQU Y8, 0(AX) + VMOVDQU Y9, 32(AX) + VZEROUPPER + + RET + +#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA +#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB +#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF +#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD +#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE + +#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7 +#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF +#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7 +#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF +#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7 +#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7 +#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF +#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF + +#define SHUFFLE_AVX() \ + VMOVDQA X6, X13; \ + VMOVDQA X2, X14; \ + VMOVDQA X4, X6; \ + VPUNPCKLQDQ_X13_X13_X15; \ + VMOVDQA X5, X4; \ + VMOVDQA X6, X5; \ + VPUNPCKHQDQ_X15_X7_X6; \ + VPUNPCKLQDQ_X7_X7_X15; \ + VPUNPCKHQDQ_X15_X13_X7; \ + VPUNPCKLQDQ_X3_X3_X15; \ + VPUNPCKHQDQ_X15_X2_X2; \ + VPUNPCKLQDQ_X14_X14_X15; \ + VPUNPCKHQDQ_X15_X3_X3; \ + +#define SHUFFLE_AVX_INV() \ + VMOVDQA X2, X13; \ + VMOVDQA X4, X14; \ + VPUNPCKLQDQ_X2_X2_X15; \ + VMOVDQA X5, X4; \ + VPUNPCKHQDQ_X15_X3_X2; \ + VMOVDQA X14, X5; \ + VPUNPCKLQDQ_X3_X3_X15; \ + VMOVDQA X6, X14; \ + VPUNPCKHQDQ_X15_X13_X3; \ + VPUNPCKLQDQ_X7_X7_X15; \ + VPUNPCKHQDQ_X15_X6_X6; \ + VPUNPCKLQDQ_X14_X14_X15; \ + VPUNPCKHQDQ_X15_X7_X7; \ + +#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ + VPADDQ m0, v0, v0; \ + VPADDQ v2, v0, v0; \ + VPADDQ m1, v1, v1; \ + VPADDQ v3, v1, v1; \ + VPXOR v0, v6, v6; \ + VPXOR v1, v7, v7; \ + VPSHUFD $-79, v6, v6; \ + VPSHUFD $-79, v7, v7; \ + VPADDQ v6, v4, v4; \ + VPADDQ v7, v5, v5; \ + VPXOR v4, v2, v2; \ + VPXOR v5, v3, v3; \ + VPSHUFB c40, v2, v2; \ + VPSHUFB c40, v3, v3; \ + VPADDQ m2, v0, v0; \ + VPADDQ v2, v0, v0; \ + VPADDQ m3, v1, v1; \ + VPADDQ v3, v1, v1; \ + VPXOR v0, v6, v6; \ + VPXOR v1, v7, v7; \ + VPSHUFB c48, v6, v6; \ + VPSHUFB c48, v7, v7; \ + VPADDQ v6, v4, v4; \ + VPADDQ v7, v5, v5; \ + VPXOR v4, v2, v2; \ + VPXOR v5, v3, v3; \ + VPADDQ v2, v2, t0; \ + VPSRLQ $63, v2, v2; \ + VPXOR t0, v2, v2; \ + VPADDQ v3, v3, t0; \ + VPSRLQ $63, v3, v3; \ + VPXOR t0, v3, v3 + +// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7) +// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0 +#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \ + VMOVQ_SI_X12(i0*8); \ + VMOVQ_SI_X13(i2*8); \ + VMOVQ_SI_X14(i4*8); \ + VMOVQ_SI_X15(i6*8); \ + VPINSRQ_1_SI_X12(i1*8); \ + VPINSRQ_1_SI_X13(i3*8); \ + VPINSRQ_1_SI_X14(i5*8); \ + VPINSRQ_1_SI_X15(i7*8) + +// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7) +#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \ + VMOVQ_SI_X12_0; \ + VMOVQ_SI_X13(4*8); \ + VMOVQ_SI_X14(1*8); \ + VMOVQ_SI_X15(5*8); \ + VPINSRQ_1_SI_X12(2*8); \ + VPINSRQ_1_SI_X13(6*8); \ + VPINSRQ_1_SI_X14(3*8); \ + VPINSRQ_1_SI_X15(7*8) + +// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3) +#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \ + VPSHUFD $0x4E, 0*8(SI), X12; \ + VMOVQ_SI_X13(11*8); \ + VMOVQ_SI_X14(12*8); \ + VMOVQ_SI_X15(7*8); \ + VPINSRQ_1_SI_X13(5*8); \ + VPINSRQ_1_SI_X14(2*8); \ + VPINSRQ_1_SI_X15(3*8) + +// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13) +#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \ + VMOVDQU 11*8(SI), X12; \ + VMOVQ_SI_X13(5*8); \ + VMOVQ_SI_X14(8*8); \ + VMOVQ_SI_X15(2*8); \ + VPINSRQ_1_SI_X13(15*8); \ + VPINSRQ_1_SI_X14_0; \ + VPINSRQ_1_SI_X15(13*8) + +// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8) +#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X13(4*8); \ + VMOVQ_SI_X14(6*8); \ + VMOVQ_SI_X15_0; \ + VPINSRQ_1_SI_X12(5*8); \ + VPINSRQ_1_SI_X13(15*8); \ + VPINSRQ_1_SI_X14(10*8); \ + VPINSRQ_1_SI_X15(8*8) + +// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15) +#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \ + VMOVQ_SI_X12(9*8); \ + VMOVQ_SI_X13(2*8); \ + VMOVQ_SI_X14_0; \ + VMOVQ_SI_X15(4*8); \ + VPINSRQ_1_SI_X12(5*8); \ + VPINSRQ_1_SI_X13(10*8); \ + VPINSRQ_1_SI_X14(7*8); \ + VPINSRQ_1_SI_X15(15*8) + +// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3) +#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \ + VMOVQ_SI_X12(2*8); \ + VMOVQ_SI_X13_0; \ + VMOVQ_SI_X14(12*8); \ + VMOVQ_SI_X15(11*8); \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X13(8*8); \ + VPINSRQ_1_SI_X14(10*8); \ + VPINSRQ_1_SI_X15(3*8) + +// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11) +#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \ + MOVQ 0*8(SI), X12; \ + VPSHUFD $0x4E, 8*8(SI), X13; \ + MOVQ 7*8(SI), X14; \ + MOVQ 2*8(SI), X15; \ + VPINSRQ_1_SI_X12(6*8); \ + VPINSRQ_1_SI_X14(3*8); \ + VPINSRQ_1_SI_X15(11*8) + +// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8) +#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \ + MOVQ 6*8(SI), X12; \ + MOVQ 11*8(SI), X13; \ + MOVQ 15*8(SI), X14; \ + MOVQ 3*8(SI), X15; \ + VPINSRQ_1_SI_X12(14*8); \ + VPINSRQ_1_SI_X13_0; \ + VPINSRQ_1_SI_X14(9*8); \ + VPINSRQ_1_SI_X15(8*8) + +// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10) +#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \ + MOVQ 5*8(SI), X12; \ + MOVQ 8*8(SI), X13; \ + MOVQ 0*8(SI), X14; \ + MOVQ 6*8(SI), X15; \ + VPINSRQ_1_SI_X12(15*8); \ + VPINSRQ_1_SI_X13(2*8); \ + VPINSRQ_1_SI_X14(4*8); \ + VPINSRQ_1_SI_X15(10*8) + +// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5) +#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \ + VMOVDQU 12*8(SI), X12; \ + MOVQ 1*8(SI), X13; \ + MOVQ 2*8(SI), X14; \ + VPINSRQ_1_SI_X13(10*8); \ + VPINSRQ_1_SI_X14(7*8); \ + VMOVDQU 4*8(SI), X15 + +// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0) +#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \ + MOVQ 15*8(SI), X12; \ + MOVQ 3*8(SI), X13; \ + MOVQ 11*8(SI), X14; \ + MOVQ 12*8(SI), X15; \ + VPINSRQ_1_SI_X12(9*8); \ + VPINSRQ_1_SI_X13(13*8); \ + VPINSRQ_1_SI_X14(14*8); \ + VPINSRQ_1_SI_X15_0 + +// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, R10 + ADDQ $15, R10 + ANDQ $~15, R10 + + VMOVDQU ·AVX_c40<>(SB), X0 + VMOVDQU ·AVX_c48<>(SB), X1 + VMOVDQA X0, X8 + VMOVDQA X1, X9 + + VMOVDQU ·AVX_iv3<>(SB), X0 + VMOVDQA X0, 0(R10) + XORQ CX, 0(R10) // 0(R10) = ·AVX_iv3 ^ (CX || 0) + + VMOVDQU 0(AX), X10 + VMOVDQU 16(AX), X11 + VMOVDQU 32(AX), X2 + VMOVDQU 48(AX), X3 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + +loop: + ADDQ $128, R8 + CMPQ R8, $128 + JGE noinc + INCQ R9 + +noinc: + VMOVQ_R8_X15 + VPINSRQ_1_R9_X15 + + VMOVDQA X10, X0 + VMOVDQA X11, X1 + VMOVDQU ·AVX_iv0<>(SB), X4 + VMOVDQU ·AVX_iv1<>(SB), X5 + VMOVDQU ·AVX_iv2<>(SB), X6 + + VPXOR X15, X6, X6 + VMOVDQA 0(R10), X7 + + LOAD_MSG_AVX_0_2_4_6_1_3_5_7() + VMOVDQA X12, 16(R10) + VMOVDQA X13, 32(R10) + VMOVDQA X14, 48(R10) + VMOVDQA X15, 64(R10) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15) + VMOVDQA X12, 80(R10) + VMOVDQA X13, 96(R10) + VMOVDQA X14, 112(R10) + VMOVDQA X15, 128(R10) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6) + VMOVDQA X12, 144(R10) + VMOVDQA X13, 160(R10) + VMOVDQA X14, 176(R10) + VMOVDQA X15, 192(R10) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_1_0_11_5_12_2_7_3() + VMOVDQA X12, 208(R10) + VMOVDQA X13, 224(R10) + VMOVDQA X14, 240(R10) + VMOVDQA X15, 256(R10) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_11_12_5_15_8_0_2_13() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_2_5_4_15_6_10_0_8() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_9_5_2_10_0_7_4_15() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_2_6_0_8_12_10_11_3() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_0_6_9_8_7_3_2_11() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_5_15_8_2_0_4_6_10() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX_6_14_11_0_15_9_3_8() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_12_13_1_10_2_7_4_5() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5) + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX() + LOAD_MSG_AVX_15_9_3_13_11_14_12_0() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9) + SHUFFLE_AVX_INV() + + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(R10), 32(R10), 48(R10), 64(R10), X15, X8, X9) + SHUFFLE_AVX() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(R10), 96(R10), 112(R10), 128(R10), X15, X8, X9) + SHUFFLE_AVX_INV() + + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(R10), 160(R10), 176(R10), 192(R10), X15, X8, X9) + SHUFFLE_AVX() + HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(R10), 224(R10), 240(R10), 256(R10), X15, X8, X9) + SHUFFLE_AVX_INV() + + VMOVDQU 32(AX), X14 + VMOVDQU 48(AX), X15 + VPXOR X0, X10, X10 + VPXOR X1, X11, X11 + VPXOR X2, X14, X14 + VPXOR X3, X15, X15 + VPXOR X4, X10, X10 + VPXOR X5, X11, X11 + VPXOR X6, X14, X2 + VPXOR X7, X15, X3 + VMOVDQU X2, 32(AX) + VMOVDQU X3, 48(AX) + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + VMOVDQU X10, 0(AX) + VMOVDQU X11, 16(AX) + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + VZEROUPPER + + RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s new file mode 100644 index 00000000000..adfac00c15c --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_amd64.s @@ -0,0 +1,278 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && gc && !purego + +#include "textflag.h" + +DATA ·iv0<>+0x00(SB)/8, $0x6a09e667f3bcc908 +DATA ·iv0<>+0x08(SB)/8, $0xbb67ae8584caa73b +GLOBL ·iv0<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv1<>+0x00(SB)/8, $0x3c6ef372fe94f82b +DATA ·iv1<>+0x08(SB)/8, $0xa54ff53a5f1d36f1 +GLOBL ·iv1<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv2<>+0x00(SB)/8, $0x510e527fade682d1 +DATA ·iv2<>+0x08(SB)/8, $0x9b05688c2b3e6c1f +GLOBL ·iv2<>(SB), (NOPTR+RODATA), $16 + +DATA ·iv3<>+0x00(SB)/8, $0x1f83d9abfb41bd6b +DATA ·iv3<>+0x08(SB)/8, $0x5be0cd19137e2179 +GLOBL ·iv3<>(SB), (NOPTR+RODATA), $16 + +DATA ·c40<>+0x00(SB)/8, $0x0201000706050403 +DATA ·c40<>+0x08(SB)/8, $0x0a09080f0e0d0c0b +GLOBL ·c40<>(SB), (NOPTR+RODATA), $16 + +DATA ·c48<>+0x00(SB)/8, $0x0100070605040302 +DATA ·c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a +GLOBL ·c48<>(SB), (NOPTR+RODATA), $16 + +#define SHUFFLE(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v6, t1; \ + PUNPCKLQDQ v6, t2; \ + PUNPCKHQDQ v7, v6; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ v7, t2; \ + MOVO t1, v7; \ + MOVO v2, t1; \ + PUNPCKHQDQ t2, v7; \ + PUNPCKLQDQ v3, t2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v3 + +#define SHUFFLE_INV(v2, v3, v4, v5, v6, v7, t1, t2) \ + MOVO v4, t1; \ + MOVO v5, v4; \ + MOVO t1, v5; \ + MOVO v2, t1; \ + PUNPCKLQDQ v2, t2; \ + PUNPCKHQDQ v3, v2; \ + PUNPCKHQDQ t2, v2; \ + PUNPCKLQDQ v3, t2; \ + MOVO t1, v3; \ + MOVO v6, t1; \ + PUNPCKHQDQ t2, v3; \ + PUNPCKLQDQ v7, t2; \ + PUNPCKHQDQ t2, v6; \ + PUNPCKLQDQ t1, t2; \ + PUNPCKHQDQ t2, v7 + +#define HALF_ROUND(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \ + PADDQ m0, v0; \ + PADDQ m1, v1; \ + PADDQ v2, v0; \ + PADDQ v3, v1; \ + PXOR v0, v6; \ + PXOR v1, v7; \ + PSHUFD $0xB1, v6, v6; \ + PSHUFD $0xB1, v7, v7; \ + PADDQ v6, v4; \ + PADDQ v7, v5; \ + PXOR v4, v2; \ + PXOR v5, v3; \ + PSHUFB c40, v2; \ + PSHUFB c40, v3; \ + PADDQ m2, v0; \ + PADDQ m3, v1; \ + PADDQ v2, v0; \ + PADDQ v3, v1; \ + PXOR v0, v6; \ + PXOR v1, v7; \ + PSHUFB c48, v6; \ + PSHUFB c48, v7; \ + PADDQ v6, v4; \ + PADDQ v7, v5; \ + PXOR v4, v2; \ + PXOR v5, v3; \ + MOVOU v2, t0; \ + PADDQ v2, t0; \ + PSRLQ $63, v2; \ + PXOR t0, v2; \ + MOVOU v3, t0; \ + PADDQ v3, t0; \ + PSRLQ $63, v3; \ + PXOR t0, v3 + +#define LOAD_MSG(m0, m1, m2, m3, src, i0, i1, i2, i3, i4, i5, i6, i7) \ + MOVQ i0*8(src), m0; \ + PINSRQ $1, i1*8(src), m0; \ + MOVQ i2*8(src), m1; \ + PINSRQ $1, i3*8(src), m1; \ + MOVQ i4*8(src), m2; \ + PINSRQ $1, i5*8(src), m2; \ + MOVQ i6*8(src), m3; \ + PINSRQ $1, i7*8(src), m3 + +// func hashBlocksSSE4(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) +TEXT ·hashBlocksSSE4(SB), 4, $288-48 // frame size = 272 + 16 byte alignment + MOVQ h+0(FP), AX + MOVQ c+8(FP), BX + MOVQ flag+16(FP), CX + MOVQ blocks_base+24(FP), SI + MOVQ blocks_len+32(FP), DI + + MOVQ SP, R10 + ADDQ $15, R10 + ANDQ $~15, R10 + + MOVOU ·iv3<>(SB), X0 + MOVO X0, 0(R10) + XORQ CX, 0(R10) // 0(R10) = ·iv3 ^ (CX || 0) + + MOVOU ·c40<>(SB), X13 + MOVOU ·c48<>(SB), X14 + + MOVOU 0(AX), X12 + MOVOU 16(AX), X15 + + MOVQ 0(BX), R8 + MOVQ 8(BX), R9 + +loop: + ADDQ $128, R8 + CMPQ R8, $128 + JGE noinc + INCQ R9 + +noinc: + MOVQ R8, X8 + PINSRQ $1, R9, X8 + + MOVO X12, X0 + MOVO X15, X1 + MOVOU 32(AX), X2 + MOVOU 48(AX), X3 + MOVOU ·iv0<>(SB), X4 + MOVOU ·iv1<>(SB), X5 + MOVOU ·iv2<>(SB), X6 + + PXOR X8, X6 + MOVO 0(R10), X7 + + LOAD_MSG(X8, X9, X10, X11, SI, 0, 2, 4, 6, 1, 3, 5, 7) + MOVO X8, 16(R10) + MOVO X9, 32(R10) + MOVO X10, 48(R10) + MOVO X11, 64(R10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 8, 10, 12, 14, 9, 11, 13, 15) + MOVO X8, 80(R10) + MOVO X9, 96(R10) + MOVO X10, 112(R10) + MOVO X11, 128(R10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 14, 4, 9, 13, 10, 8, 15, 6) + MOVO X8, 144(R10) + MOVO X9, 160(R10) + MOVO X10, 176(R10) + MOVO X11, 192(R10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 1, 0, 11, 5, 12, 2, 7, 3) + MOVO X8, 208(R10) + MOVO X9, 224(R10) + MOVO X10, 240(R10) + MOVO X11, 256(R10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 11, 12, 5, 15, 8, 0, 2, 13) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 10, 3, 7, 9, 14, 6, 1, 4) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 7, 3, 13, 11, 9, 1, 12, 14) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 2, 5, 4, 15, 6, 10, 0, 8) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 9, 5, 2, 10, 0, 7, 4, 15) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 14, 11, 6, 3, 1, 12, 8, 13) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 2, 6, 0, 8, 12, 10, 11, 3) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 4, 7, 15, 1, 13, 5, 14, 9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 12, 1, 14, 4, 5, 15, 13, 10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 0, 6, 9, 8, 7, 3, 2, 11) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 13, 7, 12, 3, 11, 14, 1, 9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 5, 15, 8, 2, 0, 4, 6, 10) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 6, 14, 11, 0, 15, 9, 3, 8) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 12, 13, 1, 10, 2, 7, 4, 5) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + LOAD_MSG(X8, X9, X10, X11, SI, 10, 8, 7, 1, 2, 4, 6, 5) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + LOAD_MSG(X8, X9, X10, X11, SI, 15, 9, 3, 13, 11, 14, 12, 0) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 16(R10), 32(R10), 48(R10), 64(R10), X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 80(R10), 96(R10), 112(R10), 128(R10), X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 144(R10), 160(R10), 176(R10), 192(R10), X11, X13, X14) + SHUFFLE(X2, X3, X4, X5, X6, X7, X8, X9) + HALF_ROUND(X0, X1, X2, X3, X4, X5, X6, X7, 208(R10), 224(R10), 240(R10), 256(R10), X11, X13, X14) + SHUFFLE_INV(X2, X3, X4, X5, X6, X7, X8, X9) + + MOVOU 32(AX), X10 + MOVOU 48(AX), X11 + PXOR X0, X12 + PXOR X1, X15 + PXOR X2, X10 + PXOR X3, X11 + PXOR X4, X12 + PXOR X5, X15 + PXOR X6, X10 + PXOR X7, X11 + MOVOU X10, 32(AX) + MOVOU X11, 48(AX) + + LEAQ 128(SI), SI + SUBQ $128, DI + JNE loop + + MOVOU X12, 0(AX) + MOVOU X15, 16(AX) + + MOVQ R8, 0(BX) + MOVQ R9, 8(BX) + + RET diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go b/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go new file mode 100644 index 00000000000..3168a8aa3c8 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_generic.go @@ -0,0 +1,182 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2b + +import ( + "encoding/binary" + "math/bits" +) + +// the precomputed values for BLAKE2b +// there are 12 16-byte arrays - one for each round +// the entries are calculated from the sigma constants. +var precomputed = [12][16]byte{ + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, + {11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4}, + {7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8}, + {9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13}, + {2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9}, + {12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11}, + {13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10}, + {6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5}, + {10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0}, + {0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15}, // equal to the first + {14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3}, // equal to the second +} + +func hashBlocksGeneric(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + var m [16]uint64 + c0, c1 := c[0], c[1] + + for i := 0; i < len(blocks); { + c0 += BlockSize + if c0 < BlockSize { + c1++ + } + + v0, v1, v2, v3, v4, v5, v6, v7 := h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7] + v8, v9, v10, v11, v12, v13, v14, v15 := iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7] + v12 ^= c0 + v13 ^= c1 + v14 ^= flag + + for j := range m { + m[j] = binary.LittleEndian.Uint64(blocks[i:]) + i += 8 + } + + for j := range precomputed { + s := &(precomputed[j]) + + v0 += m[s[0]] + v0 += v4 + v12 ^= v0 + v12 = bits.RotateLeft64(v12, -32) + v8 += v12 + v4 ^= v8 + v4 = bits.RotateLeft64(v4, -24) + v1 += m[s[1]] + v1 += v5 + v13 ^= v1 + v13 = bits.RotateLeft64(v13, -32) + v9 += v13 + v5 ^= v9 + v5 = bits.RotateLeft64(v5, -24) + v2 += m[s[2]] + v2 += v6 + v14 ^= v2 + v14 = bits.RotateLeft64(v14, -32) + v10 += v14 + v6 ^= v10 + v6 = bits.RotateLeft64(v6, -24) + v3 += m[s[3]] + v3 += v7 + v15 ^= v3 + v15 = bits.RotateLeft64(v15, -32) + v11 += v15 + v7 ^= v11 + v7 = bits.RotateLeft64(v7, -24) + + v0 += m[s[4]] + v0 += v4 + v12 ^= v0 + v12 = bits.RotateLeft64(v12, -16) + v8 += v12 + v4 ^= v8 + v4 = bits.RotateLeft64(v4, -63) + v1 += m[s[5]] + v1 += v5 + v13 ^= v1 + v13 = bits.RotateLeft64(v13, -16) + v9 += v13 + v5 ^= v9 + v5 = bits.RotateLeft64(v5, -63) + v2 += m[s[6]] + v2 += v6 + v14 ^= v2 + v14 = bits.RotateLeft64(v14, -16) + v10 += v14 + v6 ^= v10 + v6 = bits.RotateLeft64(v6, -63) + v3 += m[s[7]] + v3 += v7 + v15 ^= v3 + v15 = bits.RotateLeft64(v15, -16) + v11 += v15 + v7 ^= v11 + v7 = bits.RotateLeft64(v7, -63) + + v0 += m[s[8]] + v0 += v5 + v15 ^= v0 + v15 = bits.RotateLeft64(v15, -32) + v10 += v15 + v5 ^= v10 + v5 = bits.RotateLeft64(v5, -24) + v1 += m[s[9]] + v1 += v6 + v12 ^= v1 + v12 = bits.RotateLeft64(v12, -32) + v11 += v12 + v6 ^= v11 + v6 = bits.RotateLeft64(v6, -24) + v2 += m[s[10]] + v2 += v7 + v13 ^= v2 + v13 = bits.RotateLeft64(v13, -32) + v8 += v13 + v7 ^= v8 + v7 = bits.RotateLeft64(v7, -24) + v3 += m[s[11]] + v3 += v4 + v14 ^= v3 + v14 = bits.RotateLeft64(v14, -32) + v9 += v14 + v4 ^= v9 + v4 = bits.RotateLeft64(v4, -24) + + v0 += m[s[12]] + v0 += v5 + v15 ^= v0 + v15 = bits.RotateLeft64(v15, -16) + v10 += v15 + v5 ^= v10 + v5 = bits.RotateLeft64(v5, -63) + v1 += m[s[13]] + v1 += v6 + v12 ^= v1 + v12 = bits.RotateLeft64(v12, -16) + v11 += v12 + v6 ^= v11 + v6 = bits.RotateLeft64(v6, -63) + v2 += m[s[14]] + v2 += v7 + v13 ^= v2 + v13 = bits.RotateLeft64(v13, -16) + v8 += v13 + v7 ^= v8 + v7 = bits.RotateLeft64(v7, -63) + v3 += m[s[15]] + v3 += v4 + v14 ^= v3 + v14 = bits.RotateLeft64(v14, -16) + v9 += v14 + v4 ^= v9 + v4 = bits.RotateLeft64(v4, -63) + + } + + h[0] ^= v0 ^ v8 + h[1] ^= v1 ^ v9 + h[2] ^= v2 ^ v10 + h[3] ^= v3 ^ v11 + h[4] ^= v4 ^ v12 + h[5] ^= v5 ^ v13 + h[6] ^= v6 ^ v14 + h[7] ^= v7 ^ v15 + } + c[0], c[1] = c0, c1 +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go new file mode 100644 index 00000000000..6e28668cd19 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2b_ref.go @@ -0,0 +1,11 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !amd64 || purego || !gc + +package blake2b + +func hashBlocks(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte) { + hashBlocksGeneric(h, c, flag, blocks) +} diff --git a/vendor/golang.org/x/crypto/blake2b/blake2x.go b/vendor/golang.org/x/crypto/blake2b/blake2x.go new file mode 100644 index 00000000000..52c414db0e6 --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/blake2x.go @@ -0,0 +1,177 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2b + +import ( + "encoding/binary" + "errors" + "io" +) + +// XOF defines the interface to hash functions that +// support arbitrary-length output. +type XOF interface { + // Write absorbs more data into the hash's state. It panics if called + // after Read. + io.Writer + + // Read reads more output from the hash. It returns io.EOF if the limit + // has been reached. + io.Reader + + // Clone returns a copy of the XOF in its current state. + Clone() XOF + + // Reset resets the XOF to its initial state. + Reset() +} + +// OutputLengthUnknown can be used as the size argument to NewXOF to indicate +// the length of the output is not known in advance. +const OutputLengthUnknown = 0 + +// magicUnknownOutputLength is a magic value for the output size that indicates +// an unknown number of output bytes. +const magicUnknownOutputLength = (1 << 32) - 1 + +// maxOutputLength is the absolute maximum number of bytes to produce when the +// number of output bytes is unknown. +const maxOutputLength = (1 << 32) * 64 + +// NewXOF creates a new variable-output-length hash. The hash either produce a +// known number of bytes (1 <= size < 2**32-1), or an unknown number of bytes +// (size == OutputLengthUnknown). In the latter case, an absolute limit of +// 256GiB applies. +// +// A non-nil key turns the hash into a MAC. The key must between +// zero and 32 bytes long. +func NewXOF(size uint32, key []byte) (XOF, error) { + if len(key) > Size { + return nil, errKeySize + } + if size == magicUnknownOutputLength { + // 2^32-1 indicates an unknown number of bytes and thus isn't a + // valid length. + return nil, errors.New("blake2b: XOF length too large") + } + if size == OutputLengthUnknown { + size = magicUnknownOutputLength + } + x := &xof{ + d: digest{ + size: Size, + keyLen: len(key), + }, + length: size, + } + copy(x.d.key[:], key) + x.Reset() + return x, nil +} + +type xof struct { + d digest + length uint32 + remaining uint64 + cfg, root, block [Size]byte + offset int + nodeOffset uint32 + readMode bool +} + +func (x *xof) Write(p []byte) (n int, err error) { + if x.readMode { + panic("blake2b: write to XOF after read") + } + return x.d.Write(p) +} + +func (x *xof) Clone() XOF { + clone := *x + return &clone +} + +func (x *xof) Reset() { + x.cfg[0] = byte(Size) + binary.LittleEndian.PutUint32(x.cfg[4:], uint32(Size)) // leaf length + binary.LittleEndian.PutUint32(x.cfg[12:], x.length) // XOF length + x.cfg[17] = byte(Size) // inner hash size + + x.d.Reset() + x.d.h[1] ^= uint64(x.length) << 32 + + x.remaining = uint64(x.length) + if x.remaining == magicUnknownOutputLength { + x.remaining = maxOutputLength + } + x.offset, x.nodeOffset = 0, 0 + x.readMode = false +} + +func (x *xof) Read(p []byte) (n int, err error) { + if !x.readMode { + x.d.finalize(&x.root) + x.readMode = true + } + + if x.remaining == 0 { + return 0, io.EOF + } + + n = len(p) + if uint64(n) > x.remaining { + n = int(x.remaining) + p = p[:n] + } + + if x.offset > 0 { + blockRemaining := Size - x.offset + if n < blockRemaining { + x.offset += copy(p, x.block[x.offset:]) + x.remaining -= uint64(n) + return + } + copy(p, x.block[x.offset:]) + p = p[blockRemaining:] + x.offset = 0 + x.remaining -= uint64(blockRemaining) + } + + for len(p) >= Size { + binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) + x.nodeOffset++ + + x.d.initConfig(&x.cfg) + x.d.Write(x.root[:]) + x.d.finalize(&x.block) + + copy(p, x.block[:]) + p = p[Size:] + x.remaining -= uint64(Size) + } + + if todo := len(p); todo > 0 { + if x.remaining < uint64(Size) { + x.cfg[0] = byte(x.remaining) + } + binary.LittleEndian.PutUint32(x.cfg[8:], x.nodeOffset) + x.nodeOffset++ + + x.d.initConfig(&x.cfg) + x.d.Write(x.root[:]) + x.d.finalize(&x.block) + + x.offset = copy(p, x.block[:todo]) + x.remaining -= uint64(todo) + } + return +} + +func (d *digest) initConfig(cfg *[Size]byte) { + d.offset, d.c[0], d.c[1] = 0, 0, 0 + for i := range d.h { + d.h[i] = iv[i] ^ binary.LittleEndian.Uint64(cfg[i*8:]) + } +} diff --git a/vendor/golang.org/x/crypto/blake2b/register.go b/vendor/golang.org/x/crypto/blake2b/register.go new file mode 100644 index 00000000000..54e446e1d2c --- /dev/null +++ b/vendor/golang.org/x/crypto/blake2b/register.go @@ -0,0 +1,30 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package blake2b + +import ( + "crypto" + "hash" +) + +func init() { + newHash256 := func() hash.Hash { + h, _ := New256(nil) + return h + } + newHash384 := func() hash.Hash { + h, _ := New384(nil) + return h + } + + newHash512 := func() hash.Hash { + h, _ := New512(nil) + return h + } + + crypto.RegisterHash(crypto.BLAKE2b_256, newHash256) + crypto.RegisterHash(crypto.BLAKE2b_384, newHash384) + crypto.RegisterHash(crypto.BLAKE2b_512, newHash512) +} diff --git a/vendor/golang.org/x/crypto/hkdf/hkdf.go b/vendor/golang.org/x/crypto/hkdf/hkdf.go new file mode 100644 index 00000000000..f4ded5fee2f --- /dev/null +++ b/vendor/golang.org/x/crypto/hkdf/hkdf.go @@ -0,0 +1,95 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package hkdf implements the HMAC-based Extract-and-Expand Key Derivation +// Function (HKDF) as defined in RFC 5869. +// +// HKDF is a cryptographic key derivation function (KDF) with the goal of +// expanding limited input keying material into one or more cryptographically +// strong secret keys. +package hkdf // import "golang.org/x/crypto/hkdf" + +import ( + "crypto/hmac" + "errors" + "hash" + "io" +) + +// Extract generates a pseudorandom key for use with Expand from an input secret +// and an optional independent salt. +// +// Only use this function if you need to reuse the extracted key with multiple +// Expand invocations and different context values. Most common scenarios, +// including the generation of multiple keys, should use New instead. +func Extract(hash func() hash.Hash, secret, salt []byte) []byte { + if salt == nil { + salt = make([]byte, hash().Size()) + } + extractor := hmac.New(hash, salt) + extractor.Write(secret) + return extractor.Sum(nil) +} + +type hkdf struct { + expander hash.Hash + size int + + info []byte + counter byte + + prev []byte + buf []byte +} + +func (f *hkdf) Read(p []byte) (int, error) { + // Check whether enough data can be generated + need := len(p) + remains := len(f.buf) + int(255-f.counter+1)*f.size + if remains < need { + return 0, errors.New("hkdf: entropy limit reached") + } + // Read any leftover from the buffer + n := copy(p, f.buf) + p = p[n:] + + // Fill the rest of the buffer + for len(p) > 0 { + if f.counter > 1 { + f.expander.Reset() + } + f.expander.Write(f.prev) + f.expander.Write(f.info) + f.expander.Write([]byte{f.counter}) + f.prev = f.expander.Sum(f.prev[:0]) + f.counter++ + + // Copy the new batch into p + f.buf = f.prev + n = copy(p, f.buf) + p = p[n:] + } + // Save leftovers for next run + f.buf = f.buf[n:] + + return need, nil +} + +// Expand returns a Reader, from which keys can be read, using the given +// pseudorandom key and optional context info, skipping the extraction step. +// +// The pseudorandomKey should have been generated by Extract, or be a uniformly +// random or pseudorandom cryptographically strong key. See RFC 5869, Section +// 3.3. Most common scenarios will want to use New instead. +func Expand(hash func() hash.Hash, pseudorandomKey, info []byte) io.Reader { + expander := hmac.New(hash, pseudorandomKey) + return &hkdf{expander, expander.Size(), info, 1, nil, nil} +} + +// New returns a Reader, from which keys can be read, using the given hash, +// secret, salt and context info. Salt and info can be nil. +func New(hash func() hash.Hash, secret, salt, info []byte) io.Reader { + prk := Extract(hash, secret, salt) + return Expand(hash, prk, info) +} diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index c6492020ec7..fdcaa974d23 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -584,7 +584,7 @@ ccflags="$@" $2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || $2 ~ /^KEYCTL_/ || $2 ~ /^PERF_/ || - $2 ~ /^SECCOMP_MODE_/ || + $2 ~ /^SECCOMP_/ || $2 ~ /^SEEK_/ || $2 ~ /^SCHED_/ || $2 ~ /^SPLICE_/ || diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index a5d3ff8df95..36bf8399f4f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -1785,6 +1785,8 @@ const ( LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20 LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000 LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 + LANDLOCK_ACCESS_NET_BIND_TCP = 0x1 + LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2 LANDLOCK_CREATE_RULESET_VERSION = 0x1 LINUX_REBOOT_CMD_CAD_OFF = 0x0 LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef @@ -2465,6 +2467,7 @@ const ( PR_MCE_KILL_GET = 0x22 PR_MCE_KILL_LATE = 0x0 PR_MCE_KILL_SET = 0x1 + PR_MDWE_NO_INHERIT = 0x2 PR_MDWE_REFUSE_EXEC_GAIN = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b @@ -2669,8 +2672,9 @@ const ( RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 - RTAX_FEATURE_MASK = 0xf + RTAX_FEATURE_MASK = 0x1f RTAX_FEATURE_SACK = 0x2 + RTAX_FEATURE_TCP_USEC_TS = 0x10 RTAX_FEATURE_TIMESTAMP = 0x4 RTAX_HOPLIMIT = 0xa RTAX_INITCWND = 0xb @@ -2913,9 +2917,38 @@ const ( SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x1d SC_LOG_FLUSH = 0x100000 + SECCOMP_ADDFD_FLAG_SEND = 0x2 + SECCOMP_ADDFD_FLAG_SETFD = 0x1 + SECCOMP_FILTER_FLAG_LOG = 0x2 + SECCOMP_FILTER_FLAG_NEW_LISTENER = 0x8 + SECCOMP_FILTER_FLAG_SPEC_ALLOW = 0x4 + SECCOMP_FILTER_FLAG_TSYNC = 0x1 + SECCOMP_FILTER_FLAG_TSYNC_ESRCH = 0x10 + SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV = 0x20 + SECCOMP_GET_ACTION_AVAIL = 0x2 + SECCOMP_GET_NOTIF_SIZES = 0x3 + SECCOMP_IOCTL_NOTIF_RECV = 0xc0502100 + SECCOMP_IOCTL_NOTIF_SEND = 0xc0182101 + SECCOMP_IOC_MAGIC = '!' SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECCOMP_RET_ACTION = 0x7fff0000 + SECCOMP_RET_ACTION_FULL = 0xffff0000 + SECCOMP_RET_ALLOW = 0x7fff0000 + SECCOMP_RET_DATA = 0xffff + SECCOMP_RET_ERRNO = 0x50000 + SECCOMP_RET_KILL = 0x0 + SECCOMP_RET_KILL_PROCESS = 0x80000000 + SECCOMP_RET_KILL_THREAD = 0x0 + SECCOMP_RET_LOG = 0x7ffc0000 + SECCOMP_RET_TRACE = 0x7ff00000 + SECCOMP_RET_TRAP = 0x30000 + SECCOMP_RET_USER_NOTIF = 0x7fc00000 + SECCOMP_SET_MODE_FILTER = 0x1 + SECCOMP_SET_MODE_STRICT = 0x0 + SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP = 0x1 + SECCOMP_USER_NOTIF_FLAG_CONTINUE = 0x1 SECRETMEM_MAGIC = 0x5345434d SECURITYFS_MAGIC = 0x73636673 SEEK_CUR = 0x1 @@ -3075,6 +3108,7 @@ const ( SOL_TIPC = 0x10f SOL_TLS = 0x11a SOL_UDP = 0x11 + SOL_VSOCK = 0x11f SOL_X25 = 0x106 SOL_XDP = 0x11b SOMAXCONN = 0x1000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 4920821cf3b..42ff8c3c1b0 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index a0c1e411275..dca436004fa 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -282,6 +282,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index c63985560f6..5cca668ac30 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -288,6 +288,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 47cc62e25c1..d8cae6d1534 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -278,6 +278,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index 27ac4a09e22..28e39afdcb4 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -275,6 +275,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 54694642a5d..cd66e92cb42 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 3adb81d7582..c1595eba78e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 2dfe98f0d1b..ee9456b0da7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index f5398f84f04..8cfca81e1b5 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index c54f152d68f..60b0deb3af7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -336,6 +336,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 76057dc72fb..f90aa7281bf 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -340,6 +340,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index e0c3725e2b8..ba9e0150338 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -340,6 +340,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 18f2813ed54..07cdfd6e9fd 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -272,6 +272,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 11619d4ec88..2f1dd214a74 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -344,6 +344,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 396d994da79..f40519d9018 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -335,6 +335,9 @@ const ( SCM_TIMESTAMPNS = 0x21 SCM_TXTIME = 0x3f SCM_WIFI_STATUS = 0x25 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x400000 SFD_NONBLOCK = 0x4000 SF_FP = 0x38 diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index fcf3ecbddee..0cc3ce496e2 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -448,4 +448,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index f56dc2504ae..856d92d69ef 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -371,4 +371,7 @@ const ( SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index 974bf246767..8d467094cf5 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -412,4 +412,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 39a2739e231..edc173244d0 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -315,4 +315,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go index cf9c9d77e10..445eba20615 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go @@ -309,4 +309,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index 10b7362ef44..adba01bca70 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -432,4 +432,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 4450 SYS_CACHESTAT = 4451 SYS_FCHMODAT2 = 4452 + SYS_MAP_SHADOW_STACK = 4453 + SYS_FUTEX_WAKE = 4454 + SYS_FUTEX_WAIT = 4455 + SYS_FUTEX_REQUEUE = 4456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index cd4d8b4fd35..014c4e9c7a7 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -362,4 +362,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 5450 SYS_CACHESTAT = 5451 SYS_FCHMODAT2 = 5452 + SYS_MAP_SHADOW_STACK = 5453 + SYS_FUTEX_WAKE = 5454 + SYS_FUTEX_WAIT = 5455 + SYS_FUTEX_REQUEUE = 5456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 2c0efca818b..ccc97d74d05 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -362,4 +362,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 5450 SYS_CACHESTAT = 5451 SYS_FCHMODAT2 = 5452 + SYS_MAP_SHADOW_STACK = 5453 + SYS_FUTEX_WAKE = 5454 + SYS_FUTEX_WAIT = 5455 + SYS_FUTEX_REQUEUE = 5456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index a72e31d391d..ec2b64a95d7 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -432,4 +432,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 4450 SYS_CACHESTAT = 4451 SYS_FCHMODAT2 = 4452 + SYS_MAP_SHADOW_STACK = 4453 + SYS_FUTEX_WAKE = 4454 + SYS_FUTEX_WAIT = 4455 + SYS_FUTEX_REQUEUE = 4456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index c7d1e374713..21a839e338b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -439,4 +439,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index f4d4838c870..c11121ec3b4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -411,4 +411,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index b64f0e59114..909b631fcb4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -411,4 +411,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 95711195a06..e49bed16ea6 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -316,4 +316,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index f94e943bc4f..66017d2d32b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -377,4 +377,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index ba0c2bc5154..47bab18dced 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -390,4 +390,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index bbf8399ff58..dc0c955eecd 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -174,7 +174,8 @@ type FscryptPolicyV2 struct { Contents_encryption_mode uint8 Filenames_encryption_mode uint8 Flags uint8 - _ [4]uint8 + Log2_data_unit_size uint8 + _ [3]uint8 Master_key_identifier [16]uint8 } @@ -455,60 +456,63 @@ type Ucred struct { } type TCPInfo struct { - State uint8 - Ca_state uint8 - Retransmits uint8 - Probes uint8 - Backoff uint8 - Options uint8 - Rto uint32 - Ato uint32 - Snd_mss uint32 - Rcv_mss uint32 - Unacked uint32 - Sacked uint32 - Lost uint32 - Retrans uint32 - Fackets uint32 - Last_data_sent uint32 - Last_ack_sent uint32 - Last_data_recv uint32 - Last_ack_recv uint32 - Pmtu uint32 - Rcv_ssthresh uint32 - Rtt uint32 - Rttvar uint32 - Snd_ssthresh uint32 - Snd_cwnd uint32 - Advmss uint32 - Reordering uint32 - Rcv_rtt uint32 - Rcv_space uint32 - Total_retrans uint32 - Pacing_rate uint64 - Max_pacing_rate uint64 - Bytes_acked uint64 - Bytes_received uint64 - Segs_out uint32 - Segs_in uint32 - Notsent_bytes uint32 - Min_rtt uint32 - Data_segs_in uint32 - Data_segs_out uint32 - Delivery_rate uint64 - Busy_time uint64 - Rwnd_limited uint64 - Sndbuf_limited uint64 - Delivered uint32 - Delivered_ce uint32 - Bytes_sent uint64 - Bytes_retrans uint64 - Dsack_dups uint32 - Reord_seen uint32 - Rcv_ooopack uint32 - Snd_wnd uint32 - Rcv_wnd uint32 - Rehash uint32 + State uint8 + Ca_state uint8 + Retransmits uint8 + Probes uint8 + Backoff uint8 + Options uint8 + Rto uint32 + Ato uint32 + Snd_mss uint32 + Rcv_mss uint32 + Unacked uint32 + Sacked uint32 + Lost uint32 + Retrans uint32 + Fackets uint32 + Last_data_sent uint32 + Last_ack_sent uint32 + Last_data_recv uint32 + Last_ack_recv uint32 + Pmtu uint32 + Rcv_ssthresh uint32 + Rtt uint32 + Rttvar uint32 + Snd_ssthresh uint32 + Snd_cwnd uint32 + Advmss uint32 + Reordering uint32 + Rcv_rtt uint32 + Rcv_space uint32 + Total_retrans uint32 + Pacing_rate uint64 + Max_pacing_rate uint64 + Bytes_acked uint64 + Bytes_received uint64 + Segs_out uint32 + Segs_in uint32 + Notsent_bytes uint32 + Min_rtt uint32 + Data_segs_in uint32 + Data_segs_out uint32 + Delivery_rate uint64 + Busy_time uint64 + Rwnd_limited uint64 + Sndbuf_limited uint64 + Delivered uint32 + Delivered_ce uint32 + Bytes_sent uint64 + Bytes_retrans uint64 + Dsack_dups uint32 + Reord_seen uint32 + Rcv_ooopack uint32 + Snd_wnd uint32 + Rcv_wnd uint32 + Rehash uint32 + Total_rto uint16 + Total_rto_recoveries uint16 + Total_rto_time uint32 } type CanFilter struct { @@ -551,7 +555,7 @@ const ( SizeofIPv6MTUInfo = 0x20 SizeofICMPv6Filter = 0x20 SizeofUcred = 0xc - SizeofTCPInfo = 0xf0 + SizeofTCPInfo = 0xf8 SizeofCanFilter = 0x8 SizeofTCPRepairOpt = 0x8 ) @@ -3399,7 +3403,7 @@ const ( DEVLINK_PORT_FN_ATTR_STATE = 0x2 DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3 DEVLINK_PORT_FN_ATTR_CAPS = 0x4 - DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x4 + DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x5 ) type FsverityDigest struct { @@ -4183,7 +4187,8 @@ const ( ) type LandlockRulesetAttr struct { - Access_fs uint64 + Access_fs uint64 + Access_net uint64 } type LandlockPathBeneathAttr struct { @@ -5134,7 +5139,7 @@ const ( NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf - NL80211_FREQUENCY_ATTR_MAX = 0x1b + NL80211_FREQUENCY_ATTR_MAX = 0x1c NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc @@ -5547,7 +5552,7 @@ const ( NL80211_REGDOM_TYPE_CUSTOM_WORLD = 0x2 NL80211_REGDOM_TYPE_INTERSECTION = 0x3 NL80211_REGDOM_TYPE_WORLD = 0x1 - NL80211_REG_RULE_ATTR_MAX = 0x7 + NL80211_REG_RULE_ATTR_MAX = 0x8 NL80211_REKEY_DATA_AKM = 0x4 NL80211_REKEY_DATA_KCK = 0x2 NL80211_REKEY_DATA_KEK = 0x1 diff --git a/vendor/golang.org/x/sys/windows/env_windows.go b/vendor/golang.org/x/sys/windows/env_windows.go index b8ad1925068..d4577a42388 100644 --- a/vendor/golang.org/x/sys/windows/env_windows.go +++ b/vendor/golang.org/x/sys/windows/env_windows.go @@ -37,14 +37,17 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) { return nil, err } defer DestroyEnvironmentBlock(block) - blockp := unsafe.Pointer(block) - for { - entry := UTF16PtrToString((*uint16)(blockp)) - if len(entry) == 0 { - break + size := unsafe.Sizeof(*block) + for *block != 0 { + // find NUL terminator + end := unsafe.Pointer(block) + for *(*uint16)(end) != 0 { + end = unsafe.Add(end, size) } - env = append(env, entry) - blockp = unsafe.Add(blockp, 2*(len(entry)+1)) + + entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size) + env = append(env, UTF16ToString(entry)) + block = (*uint16)(unsafe.Add(end, size)) } return env, nil } diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index ffb8708ccf8..6395a031d45 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -125,8 +125,7 @@ func UTF16PtrToString(p *uint16) string { for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ { ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p)) } - - return string(utf16.Decode(unsafe.Slice(p, n))) + return UTF16ToString(unsafe.Slice(p, n)) } func Getpagesize() int { return 4096 } diff --git a/vendor/modules.txt b/vendor/modules.txt index 1a549f1cd2e..fafad61275a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -9,25 +9,35 @@ github.com/Azure/go-ansiterm/winterm # github.com/DataDog/zstd v1.4.5 ## explicit github.com/DataDog/zstd -# github.com/IBM/idemix v0.0.0-20220112103229-701e7610d405 -## explicit; go 1.16 +# github.com/IBM/idemix v0.0.2-0.20231011101252-a4feda90f3f7 +## explicit; go 1.19 github.com/IBM/idemix github.com/IBM/idemix/bccsp +github.com/IBM/idemix/bccsp/handlers github.com/IBM/idemix/bccsp/keystore -github.com/IBM/idemix/bccsp/schemes github.com/IBM/idemix/bccsp/schemes/dlog/bridge github.com/IBM/idemix/bccsp/schemes/dlog/crypto github.com/IBM/idemix/bccsp/schemes/dlog/crypto/translator/amcl -github.com/IBM/idemix/bccsp/schemes/dlog/handlers github.com/IBM/idemix/common/flogging github.com/IBM/idemix/common/flogging/fabenc -# github.com/IBM/mathlib v0.0.0-20220112091634-0a7378db6912 -## explicit; go 1.16 +github.com/IBM/idemix/idemixmsp +# github.com/IBM/idemix/bccsp/schemes/aries v0.0.0-20231003085036-c4470b87b2d6 +## explicit; go 1.19 +github.com/IBM/idemix/bccsp/schemes/aries +# github.com/IBM/idemix/bccsp/schemes/weak-bb v0.0.0-20240125153755-b3fcea5c7863 +## explicit; go 1.19 +github.com/IBM/idemix/bccsp/schemes/weak-bb +# github.com/IBM/idemix/bccsp/types v0.0.0-20240125153755-b3fcea5c7863 +## explicit; go 1.19 +github.com/IBM/idemix/bccsp/types +# github.com/IBM/mathlib v0.0.3-0.20231011094432-44ee0eb539da +## explicit; go 1.18 github.com/IBM/mathlib github.com/IBM/mathlib/driver github.com/IBM/mathlib/driver/amcl github.com/IBM/mathlib/driver/common github.com/IBM/mathlib/driver/gurvy +github.com/IBM/mathlib/driver/kilic # github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible ## explicit github.com/Knetic/govaluate @@ -47,6 +57,9 @@ github.com/Shopify/sarama/mocks # github.com/VictoriaMetrics/fastcache v1.9.0 ## explicit; go 1.13 github.com/VictoriaMetrics/fastcache +# github.com/ale-linux/aries-framework-go/component/kmscrypto v0.0.0-20230817163708-4b3de6d91874 +## explicit; go 1.19 +github.com/ale-linux/aries-framework-go/component/kmscrypto/crypto/primitive/bbs12381g2pub # github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 ## explicit github.com/alecthomas/template @@ -57,8 +70,8 @@ github.com/alecthomas/units # github.com/beorn7/perks v1.0.1 ## explicit; go 1.11 github.com/beorn7/perks/quantile -# github.com/bits-and-blooms/bitset v1.2.1 -## explicit; go 1.14 +# github.com/bits-and-blooms/bitset v1.13.0 +## explicit; go 1.16 github.com/bits-and-blooms/bitset # github.com/cespare/xxhash/v2 v2.2.0 ## explicit; go 1.11 @@ -66,16 +79,28 @@ github.com/cespare/xxhash/v2 # github.com/cheggaaa/pb v1.0.29 ## explicit; go 1.12 github.com/cheggaaa/pb -# github.com/consensys/gnark-crypto v0.6.0 -## explicit; go 1.16 +# github.com/consensys/bavard v0.1.13 +## explicit; go 1.15 +github.com/consensys/bavard +# github.com/consensys/gnark-crypto v0.12.1 +## explicit; go 1.18 github.com/consensys/gnark-crypto/ecc +github.com/consensys/gnark-crypto/ecc/bls12-377 +github.com/consensys/gnark-crypto/ecc/bls12-377/fp +github.com/consensys/gnark-crypto/ecc/bls12-377/fr +github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower +github.com/consensys/gnark-crypto/ecc/bls12-381 +github.com/consensys/gnark-crypto/ecc/bls12-381/fp +github.com/consensys/gnark-crypto/ecc/bls12-381/fr +github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower github.com/consensys/gnark-crypto/ecc/bn254 github.com/consensys/gnark-crypto/ecc/bn254/fp github.com/consensys/gnark-crypto/ecc/bn254/fr -github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower -github.com/consensys/gnark-crypto/field -github.com/consensys/gnark-crypto/field/internal/addchain +github.com/consensys/gnark-crypto/field/generator/config +github.com/consensys/gnark-crypto/field/generator/internal/addchain +github.com/consensys/gnark-crypto/field/hash +github.com/consensys/gnark-crypto/field/pool github.com/consensys/gnark-crypto/internal/generator/config github.com/consensys/gnark-crypto/internal/parallel # github.com/containerd/containerd v1.6.26 @@ -189,7 +214,7 @@ github.com/hashicorp/hcl/hcl/token github.com/hashicorp/hcl/json/parser github.com/hashicorp/hcl/json/scanner github.com/hashicorp/hcl/json/token -# github.com/hyperledger/fabric-amcl v0.0.0-20210603140002-2670f91851c8 +# github.com/hyperledger/fabric-amcl v0.0.0-20230602173724-9e02669dceb2 ## explicit github.com/hyperledger/fabric-amcl/amcl github.com/hyperledger/fabric-amcl/amcl/FP256BN @@ -235,6 +260,9 @@ github.com/hyperledger/fabric-protos-go/transientstore # github.com/inconshreveable/mousetrap v1.0.0 ## explicit github.com/inconshreveable/mousetrap +# github.com/kilic/bls12-381 v0.1.0 +## explicit; go 1.13 +github.com/kilic/bls12-381 # github.com/klauspost/compress v1.17.6 ## explicit; go 1.19 github.com/klauspost/compress @@ -374,8 +402,8 @@ github.com/prometheus/procfs/internal/util # github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 ## explicit github.com/rcrowley/go-metrics -# github.com/rogpeppe/go-internal v1.9.0 -## explicit; go 1.17 +# github.com/rogpeppe/go-internal v1.11.0 +## explicit; go 1.19 github.com/rogpeppe/go-internal/fmtsort # github.com/sirupsen/logrus v1.9.3 ## explicit; go 1.13 @@ -387,8 +415,8 @@ github.com/spf13/afero/mem # github.com/spf13/cast v1.3.1 ## explicit github.com/spf13/cast -# github.com/spf13/cobra v1.1.3 -## explicit; go 1.12 +# github.com/spf13/cobra v1.5.0 +## explicit; go 1.15 github.com/spf13/cobra # github.com/spf13/jwalterweatherman v1.1.0 ## explicit @@ -453,26 +481,26 @@ go.etcd.io/etcd/server/v3/etcdserver/api/snap go.etcd.io/etcd/server/v3/etcdserver/api/snap/snappb go.etcd.io/etcd/server/v3/wal go.etcd.io/etcd/server/v3/wal/walpb -# go.uber.org/atomic v1.7.0 -## explicit; go 1.13 -go.uber.org/atomic -# go.uber.org/goleak v1.1.12 -## explicit; go 1.13 -# go.uber.org/multierr v1.6.0 -## explicit; go 1.12 +# go.uber.org/multierr v1.11.0 +## explicit; go 1.19 go.uber.org/multierr -# go.uber.org/zap v1.19.0 -## explicit; go 1.13 +# go.uber.org/zap v1.26.0 +## explicit; go 1.19 go.uber.org/zap go.uber.org/zap/buffer +go.uber.org/zap/internal go.uber.org/zap/internal/bufferpool go.uber.org/zap/internal/color go.uber.org/zap/internal/exit +go.uber.org/zap/internal/pool +go.uber.org/zap/internal/stacktrace go.uber.org/zap/zapcore go.uber.org/zap/zapgrpc go.uber.org/zap/zaptest/observer -# golang.org/x/crypto v0.18.0 +# golang.org/x/crypto v0.19.0 ## explicit; go 1.18 +golang.org/x/crypto/blake2b +golang.org/x/crypto/hkdf golang.org/x/crypto/sha3 # golang.org/x/mod v0.15.0 ## explicit; go 1.18 @@ -490,7 +518,7 @@ golang.org/x/net/internal/timeseries golang.org/x/net/trace # golang.org/x/sync v0.6.0 ## explicit; go 1.18 -# golang.org/x/sys v0.16.0 +# golang.org/x/sys v0.17.0 ## explicit; go 1.18 golang.org/x/sys/cpu golang.org/x/sys/execabs @@ -642,3 +670,7 @@ gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 +# rsc.io/tmplfunc v0.0.3 +## explicit; go 1.17 +rsc.io/tmplfunc +rsc.io/tmplfunc/internal/parse diff --git a/vendor/rsc.io/tmplfunc/LICENSE b/vendor/rsc.io/tmplfunc/LICENSE new file mode 100644 index 00000000000..6a66aea5eaf --- /dev/null +++ b/vendor/rsc.io/tmplfunc/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/rsc.io/tmplfunc/README.md b/vendor/rsc.io/tmplfunc/README.md new file mode 100644 index 00000000000..8e3d917c410 --- /dev/null +++ b/vendor/rsc.io/tmplfunc/README.md @@ -0,0 +1,8 @@ +[![Documentation](https://pkg.go.dev/badge/rsc.io/tmplfunc.svg)](https://pkg.go.dev/rsc.io/tmplfunc) + +Package tmplfunc provides an extension of Go templates +in which templates can be invoked as if they were functions. + +See the [package documentation](https://pkg.go.dev/rsc.io/tmplfunc) for details. + + diff --git a/vendor/rsc.io/tmplfunc/func.go b/vendor/rsc.io/tmplfunc/func.go new file mode 100644 index 00000000000..4366d1f4fd5 --- /dev/null +++ b/vendor/rsc.io/tmplfunc/func.go @@ -0,0 +1,205 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tmplfunc + +import ( + "bytes" + "fmt" + "reflect" + "regexp" + "strings" + + "rsc.io/tmplfunc/internal/parse" + + htmltemplate "html/template" + texttemplate "text/template" +) + +var validNameRE = regexp.MustCompile(`\A[_\pL][_\pL\p{Nd}]*\z`) +var validArgNameRE = regexp.MustCompile(`\A[_\pL][_\pL\p{Nd}]*(\.\.\.|\?)?\z`) + +func funcs(t Template, names, texts []string) error { + var leftDelim, rightDelim string + switch t := t.(type) { + case nil: + return fmt.Errorf("tmplfunc: nil Template") + default: + return fmt.Errorf("tmplfunc: non-template type %T", t) + case *texttemplate.Template: + leftDelim = reflect.ValueOf(t).Elem().FieldByName("leftDelim").String() + rightDelim = reflect.ValueOf(t).Elem().FieldByName("rightDelim").String() + case *htmltemplate.Template: + leftDelim = reflect.ValueOf(t).Elem().FieldByName("text").Elem().FieldByName("leftDelim").String() + rightDelim = reflect.ValueOf(t).Elem().FieldByName("text").Elem().FieldByName("rightDelim").String() + } + + trees := make(map[string]*parse.Tree) + for i, text := range texts { + t := parse.New(names[i], nil) + t.Mode = parse.SkipFuncCheck + _, err := t.Parse(text, leftDelim, rightDelim, trees) + if err != nil { + return err + } + } + + // Install functions for named templates as appropriate. + funcs := make(map[string]interface{}) + for name := range trees { + if err := addFunc(t, name, funcs); err != nil { + return err + } + } + + switch t := t.(type) { + case *texttemplate.Template: + t.Funcs(funcs) + case *htmltemplate.Template: + t.Funcs(funcs) + } + + return nil +} + +// Funcs installs functions for all the templates in the set containing t. +// After using t.Clone it is necessary to call Funcs on the result to arrange +// for the functions to invoke the cloned templates and not the originals. +func Funcs(t Template) error { + funcs := make(map[string]interface{}) + switch t := t.(type) { + case *texttemplate.Template: + for _, t1 := range t.Templates() { + if err := addFunc(t, t1.Name(), funcs); err != nil { + return err + } + } + t.Funcs(funcs) + case *htmltemplate.Template: + for _, t1 := range t.Templates() { + if err := addFunc(t, t1.Name(), funcs); err != nil { + return err + } + } + t.Funcs(funcs) + } + return nil +} + +func addFunc(t Template, name string, funcs map[string]interface{}) error { + fn, bundle, err := bundler(name) + if err != nil { + return err + } + if fn == "" { + return nil + } + switch t := t.(type) { + case *texttemplate.Template: + funcs[fn] = func(args ...interface{}) (string, error) { + t := t.Lookup(name) + if t == nil { + return "", fmt.Errorf("lost template %q", name) + } + arg, err := bundle(args) + if err != nil { + return "", err + } + var buf bytes.Buffer + err = t.Execute(&buf, arg) + if err != nil { + return "", err + } + return buf.String(), nil + } + case *htmltemplate.Template: + funcs[fn] = func(args ...interface{}) (htmltemplate.HTML, error) { + t := t.Lookup(name) + if t == nil { + return "", fmt.Errorf("lost template %q", name) + } + arg, err := bundle(args) + if err != nil { + return "", err + } + var buf bytes.Buffer + err = t.Execute(&buf, arg) + if err != nil { + return "", err + } + return htmltemplate.HTML(buf.String()), nil + } + } + return nil +} + +func bundler(name string) (fn string, bundle func(args []interface{}) (interface{}, error), err error) { + f := strings.Fields(name) + if len(f) == 0 || !validNameRE.MatchString(f[0]) { + return "", nil, nil + } + + fn = f[0] + if len(f) == 1 { + bundle = func(args []interface{}) (interface{}, error) { + if len(args) == 0 { + return nil, nil + } + if len(args) == 1 { + return args[0], nil + } + return nil, fmt.Errorf("too many arguments in call to template %s", fn) + } + } else { + sawQ := false + for i, argName := range f[1:] { + if !validArgNameRE.MatchString(argName) { + return "", nil, fmt.Errorf("invalid template name %q: invalid argument name %s", name, argName) + } + if strings.HasSuffix(argName, "...") { + if i != len(f)-2 { + return "", nil, fmt.Errorf("invalid template name %q: %s is not last argument", name, argName) + } + break + } + if strings.HasSuffix(argName, "?") { + sawQ = true + continue + } + if sawQ { + return "", nil, fmt.Errorf("invalid template name %q: required %s after optional %s", name, argName, f[i]) + } + } + + bundle = func(args []interface{}) (interface{}, error) { + m := make(map[string]interface{}) + for _, argName := range f[1:] { + if strings.HasSuffix(argName, "...") { + m[strings.TrimSuffix(argName, "...")] = args + args = nil + break + } + if strings.HasSuffix(argName, "?") { + prefix := strings.TrimSuffix(argName, "?") + if len(args) == 0 { + m[prefix] = nil + } else { + m[prefix], args = args[0], args[1:] + } + continue + } + if len(args) == 0 { + return nil, fmt.Errorf("too few arguments in call to template %s", fn) + } + m[argName], args = args[0], args[1:] + } + if len(args) > 0 { + return nil, fmt.Errorf("too many arguments in call to template %s", fn) + } + return m, nil + } + } + + return fn, bundle, nil +} diff --git a/vendor/rsc.io/tmplfunc/internal/parse/lex.go b/vendor/rsc.io/tmplfunc/internal/parse/lex.go new file mode 100644 index 00000000000..6784071b111 --- /dev/null +++ b/vendor/rsc.io/tmplfunc/internal/parse/lex.go @@ -0,0 +1,671 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package parse + +import ( + "fmt" + "strings" + "unicode" + "unicode/utf8" +) + +// item represents a token or text string returned from the scanner. +type item struct { + typ itemType // The type of this item. + pos Pos // The starting position, in bytes, of this item in the input string. + val string // The value of this item. + line int // The line number at the start of this item. +} + +func (i item) String() string { + switch { + case i.typ == itemEOF: + return "EOF" + case i.typ == itemError: + return i.val + case i.typ > itemKeyword: + return fmt.Sprintf("<%s>", i.val) + case len(i.val) > 10: + return fmt.Sprintf("%.10q...", i.val) + } + return fmt.Sprintf("%q", i.val) +} + +// itemType identifies the type of lex items. +type itemType int + +const ( + itemError itemType = iota // error occurred; value is text of error + itemBool // boolean constant + itemChar // printable ASCII character; grab bag for comma etc. + itemCharConstant // character constant + itemComment // comment text + itemComplex // complex constant (1+2i); imaginary is just a number + itemAssign // equals ('=') introducing an assignment + itemDeclare // colon-equals (':=') introducing a declaration + itemEOF + itemField // alphanumeric identifier starting with '.' + itemIdentifier // alphanumeric identifier not starting with '.' + itemLeftDelim // left action delimiter + itemLeftParen // '(' inside action + itemNumber // simple number, including imaginary + itemPipe // pipe symbol + itemRawString // raw quoted string (includes quotes) + itemRightDelim // right action delimiter + itemRightParen // ')' inside action + itemSpace // run of spaces separating arguments + itemString // quoted string (includes quotes) + itemText // plain text + itemVariable // variable starting with '$', such as '$' or '$1' or '$hello' + // Keywords appear after all the rest. + itemKeyword // used only to delimit the keywords + itemBlock // block keyword + itemDot // the cursor, spelled '.' + itemDefine // define keyword + itemElse // else keyword + itemEnd // end keyword + itemIf // if keyword + itemNil // the untyped nil constant, easiest to treat as a keyword + itemRange // range keyword + itemTemplate // template keyword + itemWith // with keyword +) + +var key = map[string]itemType{ + ".": itemDot, + "block": itemBlock, + "define": itemDefine, + "else": itemElse, + "end": itemEnd, + "if": itemIf, + "range": itemRange, + "nil": itemNil, + "template": itemTemplate, + "with": itemWith, +} + +const eof = -1 + +// Trimming spaces. +// If the action begins "{{- " rather than "{{", then all space/tab/newlines +// preceding the action are trimmed; conversely if it ends " -}}" the +// leading spaces are trimmed. This is done entirely in the lexer; the +// parser never sees it happen. We require an ASCII space (' ', \t, \r, \n) +// to be present to avoid ambiguity with things like "{{-3}}". It reads +// better with the space present anyway. For simplicity, only ASCII +// does the job. +const ( + spaceChars = " \t\r\n" // These are the space characters defined by Go itself. + trimMarker = '-' // Attached to left/right delimiter, trims trailing spaces from preceding/following text. + trimMarkerLen = Pos(1 + 1) // marker plus space before or after +) + +// stateFn represents the state of the scanner as a function that returns the next state. +type stateFn func(*lexer) stateFn + +// lexer holds the state of the scanner. +type lexer struct { + name string // the name of the input; used only for error reports + input string // the string being scanned + leftDelim string // start of action + rightDelim string // end of action + emitComment bool // emit itemComment tokens. + pos Pos // current position in the input + start Pos // start position of this item + width Pos // width of last rune read from input + items chan item // channel of scanned items + parenDepth int // nesting depth of ( ) exprs + line int // 1+number of newlines seen + startLine int // start line of this item +} + +// next returns the next rune in the input. +func (l *lexer) next() rune { + if int(l.pos) >= len(l.input) { + l.width = 0 + return eof + } + r, w := utf8.DecodeRuneInString(l.input[l.pos:]) + l.width = Pos(w) + l.pos += l.width + if r == '\n' { + l.line++ + } + return r +} + +// peek returns but does not consume the next rune in the input. +func (l *lexer) peek() rune { + r := l.next() + l.backup() + return r +} + +// backup steps back one rune. Can only be called once per call of next. +func (l *lexer) backup() { + l.pos -= l.width + // Correct newline count. + if l.width == 1 && l.input[l.pos] == '\n' { + l.line-- + } +} + +// emit passes an item back to the client. +func (l *lexer) emit(t itemType) { + l.items <- item{t, l.start, l.input[l.start:l.pos], l.startLine} + l.start = l.pos + l.startLine = l.line +} + +// ignore skips over the pending input before this point. +func (l *lexer) ignore() { + l.line += strings.Count(l.input[l.start:l.pos], "\n") + l.start = l.pos + l.startLine = l.line +} + +// accept consumes the next rune if it's from the valid set. +func (l *lexer) accept(valid string) bool { + if strings.ContainsRune(valid, l.next()) { + return true + } + l.backup() + return false +} + +// acceptRun consumes a run of runes from the valid set. +func (l *lexer) acceptRun(valid string) { + for strings.ContainsRune(valid, l.next()) { + } + l.backup() +} + +// errorf returns an error token and terminates the scan by passing +// back a nil pointer that will be the next state, terminating l.nextItem. +func (l *lexer) errorf(format string, args ...interface{}) stateFn { + l.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.startLine} + return nil +} + +// nextItem returns the next item from the input. +// Called by the parser, not in the lexing goroutine. +func (l *lexer) nextItem() item { + return <-l.items +} + +// drain drains the output so the lexing goroutine will exit. +// Called by the parser, not in the lexing goroutine. +func (l *lexer) drain() { + for range l.items { + } +} + +// lex creates a new scanner for the input string. +func lex(name, input, left, right string, emitComment bool) *lexer { + if left == "" { + left = leftDelim + } + if right == "" { + right = rightDelim + } + l := &lexer{ + name: name, + input: input, + leftDelim: left, + rightDelim: right, + emitComment: emitComment, + items: make(chan item), + line: 1, + startLine: 1, + } + go l.run() + return l +} + +// run runs the state machine for the lexer. +func (l *lexer) run() { + for state := lexText; state != nil; { + state = state(l) + } + close(l.items) +} + +// state functions + +const ( + leftDelim = "{{" + rightDelim = "}}" + leftComment = "/*" + rightComment = "*/" +) + +// lexText scans until an opening action delimiter, "{{". +func lexText(l *lexer) stateFn { + l.width = 0 + if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 { + ldn := Pos(len(l.leftDelim)) + l.pos += Pos(x) + trimLength := Pos(0) + if hasLeftTrimMarker(l.input[l.pos+ldn:]) { + trimLength = rightTrimLength(l.input[l.start:l.pos]) + } + l.pos -= trimLength + if l.pos > l.start { + l.line += strings.Count(l.input[l.start:l.pos], "\n") + l.emit(itemText) + } + l.pos += trimLength + l.ignore() + return lexLeftDelim + } + l.pos = Pos(len(l.input)) + // Correctly reached EOF. + if l.pos > l.start { + l.line += strings.Count(l.input[l.start:l.pos], "\n") + l.emit(itemText) + } + l.emit(itemEOF) + return nil +} + +// rightTrimLength returns the length of the spaces at the end of the string. +func rightTrimLength(s string) Pos { + return Pos(len(s) - len(strings.TrimRight(s, spaceChars))) +} + +// atRightDelim reports whether the lexer is at a right delimiter, possibly preceded by a trim marker. +func (l *lexer) atRightDelim() (delim, trimSpaces bool) { + if hasRightTrimMarker(l.input[l.pos:]) && strings.HasPrefix(l.input[l.pos+trimMarkerLen:], l.rightDelim) { // With trim marker. + return true, true + } + if strings.HasPrefix(l.input[l.pos:], l.rightDelim) { // Without trim marker. + return true, false + } + return false, false +} + +// leftTrimLength returns the length of the spaces at the beginning of the string. +func leftTrimLength(s string) Pos { + return Pos(len(s) - len(strings.TrimLeft(s, spaceChars))) +} + +// lexLeftDelim scans the left delimiter, which is known to be present, possibly with a trim marker. +func lexLeftDelim(l *lexer) stateFn { + l.pos += Pos(len(l.leftDelim)) + trimSpace := hasLeftTrimMarker(l.input[l.pos:]) + afterMarker := Pos(0) + if trimSpace { + afterMarker = trimMarkerLen + } + if strings.HasPrefix(l.input[l.pos+afterMarker:], leftComment) { + l.pos += afterMarker + l.ignore() + return lexComment + } + l.emit(itemLeftDelim) + l.pos += afterMarker + l.ignore() + l.parenDepth = 0 + return lexInsideAction +} + +// lexComment scans a comment. The left comment marker is known to be present. +func lexComment(l *lexer) stateFn { + l.pos += Pos(len(leftComment)) + i := strings.Index(l.input[l.pos:], rightComment) + if i < 0 { + return l.errorf("unclosed comment") + } + l.pos += Pos(i + len(rightComment)) + delim, trimSpace := l.atRightDelim() + if !delim { + return l.errorf("comment ends before closing delimiter") + } + if l.emitComment { + l.emit(itemComment) + } + if trimSpace { + l.pos += trimMarkerLen + } + l.pos += Pos(len(l.rightDelim)) + if trimSpace { + l.pos += leftTrimLength(l.input[l.pos:]) + } + l.ignore() + return lexText +} + +// lexRightDelim scans the right delimiter, which is known to be present, possibly with a trim marker. +func lexRightDelim(l *lexer) stateFn { + trimSpace := hasRightTrimMarker(l.input[l.pos:]) + if trimSpace { + l.pos += trimMarkerLen + l.ignore() + } + l.pos += Pos(len(l.rightDelim)) + l.emit(itemRightDelim) + if trimSpace { + l.pos += leftTrimLength(l.input[l.pos:]) + l.ignore() + } + return lexText +} + +// lexInsideAction scans the elements inside action delimiters. +func lexInsideAction(l *lexer) stateFn { + // Either number, quoted string, or identifier. + // Spaces separate arguments; runs of spaces turn into itemSpace. + // Pipe symbols separate and are emitted. + delim, _ := l.atRightDelim() + if delim { + if l.parenDepth == 0 { + return lexRightDelim + } + return l.errorf("unclosed left paren") + } + switch r := l.next(); { + case r == eof: + return l.errorf("unclosed action") + case isSpace(r): + l.backup() // Put space back in case we have " -}}". + return lexSpace + case r == '=': + l.emit(itemAssign) + case r == ':': + if l.next() != '=' { + return l.errorf("expected :=") + } + l.emit(itemDeclare) + case r == '|': + l.emit(itemPipe) + case r == '"': + return lexQuote + case r == '`': + return lexRawQuote + case r == '$': + return lexVariable + case r == '\'': + return lexChar + case r == '.': + // special look-ahead for ".field" so we don't break l.backup(). + if l.pos < Pos(len(l.input)) { + r := l.input[l.pos] + if r < '0' || '9' < r { + return lexField + } + } + fallthrough // '.' can start a number. + case r == '+' || r == '-' || ('0' <= r && r <= '9'): + l.backup() + return lexNumber + case isAlphaNumeric(r): + l.backup() + return lexIdentifier + case r == '(': + l.emit(itemLeftParen) + l.parenDepth++ + case r == ')': + l.emit(itemRightParen) + l.parenDepth-- + if l.parenDepth < 0 { + return l.errorf("unexpected right paren %#U", r) + } + case r <= unicode.MaxASCII && unicode.IsPrint(r): + l.emit(itemChar) + default: + return l.errorf("unrecognized character in action: %#U", r) + } + return lexInsideAction +} + +// lexSpace scans a run of space characters. +// We have not consumed the first space, which is known to be present. +// Take care if there is a trim-marked right delimiter, which starts with a space. +func lexSpace(l *lexer) stateFn { + var r rune + var numSpaces int + for { + r = l.peek() + if !isSpace(r) { + break + } + l.next() + numSpaces++ + } + // Be careful about a trim-marked closing delimiter, which has a minus + // after a space. We know there is a space, so check for the '-' that might follow. + if hasRightTrimMarker(l.input[l.pos-1:]) && strings.HasPrefix(l.input[l.pos-1+trimMarkerLen:], l.rightDelim) { + l.backup() // Before the space. + if numSpaces == 1 { + return lexRightDelim // On the delim, so go right to that. + } + } + l.emit(itemSpace) + return lexInsideAction +} + +// lexIdentifier scans an alphanumeric. +func lexIdentifier(l *lexer) stateFn { +Loop: + for { + switch r := l.next(); { + case isAlphaNumeric(r): + // absorb. + default: + l.backup() + word := l.input[l.start:l.pos] + if !l.atTerminator() { + return l.errorf("bad character %#U", r) + } + switch { + case key[word] > itemKeyword: + l.emit(key[word]) + case word[0] == '.': + l.emit(itemField) + case word == "true", word == "false": + l.emit(itemBool) + default: + l.emit(itemIdentifier) + } + break Loop + } + } + return lexInsideAction +} + +// lexField scans a field: .Alphanumeric. +// The . has been scanned. +func lexField(l *lexer) stateFn { + return lexFieldOrVariable(l, itemField) +} + +// lexVariable scans a Variable: $Alphanumeric. +// The $ has been scanned. +func lexVariable(l *lexer) stateFn { + if l.atTerminator() { // Nothing interesting follows -> "$". + l.emit(itemVariable) + return lexInsideAction + } + return lexFieldOrVariable(l, itemVariable) +} + +// lexVariable scans a field or variable: [.$]Alphanumeric. +// The . or $ has been scanned. +func lexFieldOrVariable(l *lexer, typ itemType) stateFn { + if l.atTerminator() { // Nothing interesting follows -> "." or "$". + if typ == itemVariable { + l.emit(itemVariable) + } else { + l.emit(itemDot) + } + return lexInsideAction + } + var r rune + for { + r = l.next() + if !isAlphaNumeric(r) { + l.backup() + break + } + } + if !l.atTerminator() { + return l.errorf("bad character %#U", r) + } + l.emit(typ) + return lexInsideAction +} + +// atTerminator reports whether the input is at valid termination character to +// appear after an identifier. Breaks .X.Y into two pieces. Also catches cases +// like "$x+2" not being acceptable without a space, in case we decide one +// day to implement arithmetic. +func (l *lexer) atTerminator() bool { + r := l.peek() + if isSpace(r) { + return true + } + switch r { + case eof, '.', ',', '|', ':', ')', '(': + return true + } + // Does r start the delimiter? This can be ambiguous (with delim=="//", $x/2 will + // succeed but should fail) but only in extremely rare cases caused by willfully + // bad choice of delimiter. + if rd, _ := utf8.DecodeRuneInString(l.rightDelim); rd == r { + return true + } + return false +} + +// lexChar scans a character constant. The initial quote is already +// scanned. Syntax checking is done by the parser. +func lexChar(l *lexer) stateFn { +Loop: + for { + switch l.next() { + case '\\': + if r := l.next(); r != eof && r != '\n' { + break + } + fallthrough + case eof, '\n': + return l.errorf("unterminated character constant") + case '\'': + break Loop + } + } + l.emit(itemCharConstant) + return lexInsideAction +} + +// lexNumber scans a number: decimal, octal, hex, float, or imaginary. This +// isn't a perfect number scanner - for instance it accepts "." and "0x0.2" +// and "089" - but when it's wrong the input is invalid and the parser (via +// strconv) will notice. +func lexNumber(l *lexer) stateFn { + if !l.scanNumber() { + return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) + } + if sign := l.peek(); sign == '+' || sign == '-' { + // Complex: 1+2i. No spaces, must end in 'i'. + if !l.scanNumber() || l.input[l.pos-1] != 'i' { + return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) + } + l.emit(itemComplex) + } else { + l.emit(itemNumber) + } + return lexInsideAction +} + +func (l *lexer) scanNumber() bool { + // Optional leading sign. + l.accept("+-") + // Is it hex? + digits := "0123456789_" + if l.accept("0") { + // Note: Leading 0 does not mean octal in floats. + if l.accept("xX") { + digits = "0123456789abcdefABCDEF_" + } else if l.accept("oO") { + digits = "01234567_" + } else if l.accept("bB") { + digits = "01_" + } + } + l.acceptRun(digits) + if l.accept(".") { + l.acceptRun(digits) + } + if len(digits) == 10+1 && l.accept("eE") { + l.accept("+-") + l.acceptRun("0123456789_") + } + if len(digits) == 16+6+1 && l.accept("pP") { + l.accept("+-") + l.acceptRun("0123456789_") + } + // Is it imaginary? + l.accept("i") + // Next thing mustn't be alphanumeric. + if isAlphaNumeric(l.peek()) { + l.next() + return false + } + return true +} + +// lexQuote scans a quoted string. +func lexQuote(l *lexer) stateFn { +Loop: + for { + switch l.next() { + case '\\': + if r := l.next(); r != eof && r != '\n' { + break + } + fallthrough + case eof, '\n': + return l.errorf("unterminated quoted string") + case '"': + break Loop + } + } + l.emit(itemString) + return lexInsideAction +} + +// lexRawQuote scans a raw quoted string. +func lexRawQuote(l *lexer) stateFn { +Loop: + for { + switch l.next() { + case eof: + return l.errorf("unterminated raw quoted string") + case '`': + break Loop + } + } + l.emit(itemRawString) + return lexInsideAction +} + +// isSpace reports whether r is a space character. +func isSpace(r rune) bool { + return r == ' ' || r == '\t' || r == '\r' || r == '\n' +} + +// isAlphaNumeric reports whether r is an alphabetic, digit, or underscore. +func isAlphaNumeric(r rune) bool { + return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r) +} + +func hasLeftTrimMarker(s string) bool { + return len(s) >= 2 && s[0] == trimMarker && isSpace(rune(s[1])) +} + +func hasRightTrimMarker(s string) bool { + return len(s) >= 2 && isSpace(rune(s[0])) && s[1] == trimMarker +} diff --git a/vendor/rsc.io/tmplfunc/internal/parse/node.go b/vendor/rsc.io/tmplfunc/internal/parse/node.go new file mode 100644 index 00000000000..177482f9b26 --- /dev/null +++ b/vendor/rsc.io/tmplfunc/internal/parse/node.go @@ -0,0 +1,972 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Parse nodes. + +package parse + +import ( + "fmt" + "strconv" + "strings" +) + +var textFormat = "%s" // Changed to "%q" in tests for better error messages. + +// A Node is an element in the parse tree. The interface is trivial. +// The interface contains an unexported method so that only +// types local to this package can satisfy it. +type Node interface { + Type() NodeType + String() string + // Copy does a deep copy of the Node and all its components. + // To avoid type assertions, some XxxNodes also have specialized + // CopyXxx methods that return *XxxNode. + Copy() Node + Position() Pos // byte position of start of node in full original input string + // tree returns the containing *Tree. + // It is unexported so all implementations of Node are in this package. + tree() *Tree + // writeTo writes the String output to the builder. + writeTo(*strings.Builder) +} + +// NodeType identifies the type of a parse tree node. +type NodeType int + +// Pos represents a byte position in the original input text from which +// this template was parsed. +type Pos int + +func (p Pos) Position() Pos { + return p +} + +// Type returns itself and provides an easy default implementation +// for embedding in a Node. Embedded in all non-trivial Nodes. +func (t NodeType) Type() NodeType { + return t +} + +const ( + NodeText NodeType = iota // Plain text. + NodeAction // A non-control action such as a field evaluation. + NodeBool // A boolean constant. + NodeChain // A sequence of field accesses. + NodeCommand // An element of a pipeline. + NodeDot // The cursor, dot. + nodeElse // An else action. Not added to tree. + nodeEnd // An end action. Not added to tree. + NodeField // A field or method name. + NodeIdentifier // An identifier; always a function name. + NodeIf // An if action. + NodeList // A list of Nodes. + NodeNil // An untyped nil constant. + NodeNumber // A numerical constant. + NodePipe // A pipeline of commands. + NodeRange // A range action. + NodeString // A string constant. + NodeTemplate // A template invocation action. + NodeVariable // A $ variable. + NodeWith // A with action. + NodeComment // A comment. +) + +// Nodes. + +// ListNode holds a sequence of nodes. +type ListNode struct { + NodeType + Pos + tr *Tree + Nodes []Node // The element nodes in lexical order. +} + +func (t *Tree) newList(pos Pos) *ListNode { + return &ListNode{tr: t, NodeType: NodeList, Pos: pos} +} + +func (l *ListNode) append(n Node) { + l.Nodes = append(l.Nodes, n) +} + +func (l *ListNode) tree() *Tree { + return l.tr +} + +func (l *ListNode) String() string { + var sb strings.Builder + l.writeTo(&sb) + return sb.String() +} + +func (l *ListNode) writeTo(sb *strings.Builder) { + for _, n := range l.Nodes { + n.writeTo(sb) + } +} + +func (l *ListNode) CopyList() *ListNode { + if l == nil { + return l + } + n := l.tr.newList(l.Pos) + for _, elem := range l.Nodes { + n.append(elem.Copy()) + } + return n +} + +func (l *ListNode) Copy() Node { + return l.CopyList() +} + +// TextNode holds plain text. +type TextNode struct { + NodeType + Pos + tr *Tree + Text []byte // The text; may span newlines. +} + +func (t *Tree) newText(pos Pos, text string) *TextNode { + return &TextNode{tr: t, NodeType: NodeText, Pos: pos, Text: []byte(text)} +} + +func (t *TextNode) String() string { + return fmt.Sprintf(textFormat, t.Text) +} + +func (t *TextNode) writeTo(sb *strings.Builder) { + sb.WriteString(t.String()) +} + +func (t *TextNode) tree() *Tree { + return t.tr +} + +func (t *TextNode) Copy() Node { + return &TextNode{tr: t.tr, NodeType: NodeText, Pos: t.Pos, Text: append([]byte{}, t.Text...)} +} + +// CommentNode holds a comment. +type CommentNode struct { + NodeType + Pos + tr *Tree + Text string // Comment text. +} + +func (t *Tree) newComment(pos Pos, text string) *CommentNode { + return &CommentNode{tr: t, NodeType: NodeComment, Pos: pos, Text: text} +} + +func (c *CommentNode) String() string { + var sb strings.Builder + c.writeTo(&sb) + return sb.String() +} + +func (c *CommentNode) writeTo(sb *strings.Builder) { + sb.WriteString("{{") + sb.WriteString(c.Text) + sb.WriteString("}}") +} + +func (c *CommentNode) tree() *Tree { + return c.tr +} + +func (c *CommentNode) Copy() Node { + return &CommentNode{tr: c.tr, NodeType: NodeComment, Pos: c.Pos, Text: c.Text} +} + +// PipeNode holds a pipeline with optional declaration +type PipeNode struct { + NodeType + Pos + tr *Tree + Line int // The line number in the input. Deprecated: Kept for compatibility. + IsAssign bool // The variables are being assigned, not declared. + Decl []*VariableNode // Variables in lexical order. + Cmds []*CommandNode // The commands in lexical order. +} + +func (t *Tree) newPipeline(pos Pos, line int, vars []*VariableNode) *PipeNode { + return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: vars} +} + +func (p *PipeNode) append(command *CommandNode) { + p.Cmds = append(p.Cmds, command) +} + +func (p *PipeNode) String() string { + var sb strings.Builder + p.writeTo(&sb) + return sb.String() +} + +func (p *PipeNode) writeTo(sb *strings.Builder) { + if len(p.Decl) > 0 { + for i, v := range p.Decl { + if i > 0 { + sb.WriteString(", ") + } + v.writeTo(sb) + } + sb.WriteString(" := ") + } + for i, c := range p.Cmds { + if i > 0 { + sb.WriteString(" | ") + } + c.writeTo(sb) + } +} + +func (p *PipeNode) tree() *Tree { + return p.tr +} + +func (p *PipeNode) CopyPipe() *PipeNode { + if p == nil { + return p + } + vars := make([]*VariableNode, len(p.Decl)) + for i, d := range p.Decl { + vars[i] = d.Copy().(*VariableNode) + } + n := p.tr.newPipeline(p.Pos, p.Line, vars) + n.IsAssign = p.IsAssign + for _, c := range p.Cmds { + n.append(c.Copy().(*CommandNode)) + } + return n +} + +func (p *PipeNode) Copy() Node { + return p.CopyPipe() +} + +// ActionNode holds an action (something bounded by delimiters). +// Control actions have their own nodes; ActionNode represents simple +// ones such as field evaluations and parenthesized pipelines. +type ActionNode struct { + NodeType + Pos + tr *Tree + Line int // The line number in the input. Deprecated: Kept for compatibility. + Pipe *PipeNode // The pipeline in the action. +} + +func (t *Tree) newAction(pos Pos, line int, pipe *PipeNode) *ActionNode { + return &ActionNode{tr: t, NodeType: NodeAction, Pos: pos, Line: line, Pipe: pipe} +} + +func (a *ActionNode) String() string { + var sb strings.Builder + a.writeTo(&sb) + return sb.String() +} + +func (a *ActionNode) writeTo(sb *strings.Builder) { + sb.WriteString("{{") + a.Pipe.writeTo(sb) + sb.WriteString("}}") +} + +func (a *ActionNode) tree() *Tree { + return a.tr +} + +func (a *ActionNode) Copy() Node { + return a.tr.newAction(a.Pos, a.Line, a.Pipe.CopyPipe()) + +} + +// CommandNode holds a command (a pipeline inside an evaluating action). +type CommandNode struct { + NodeType + Pos + tr *Tree + Args []Node // Arguments in lexical order: Identifier, field, or constant. +} + +func (t *Tree) newCommand(pos Pos) *CommandNode { + return &CommandNode{tr: t, NodeType: NodeCommand, Pos: pos} +} + +func (c *CommandNode) append(arg Node) { + c.Args = append(c.Args, arg) +} + +func (c *CommandNode) String() string { + var sb strings.Builder + c.writeTo(&sb) + return sb.String() +} + +func (c *CommandNode) writeTo(sb *strings.Builder) { + for i, arg := range c.Args { + if i > 0 { + sb.WriteByte(' ') + } + if arg, ok := arg.(*PipeNode); ok { + sb.WriteByte('(') + arg.writeTo(sb) + sb.WriteByte(')') + continue + } + arg.writeTo(sb) + } +} + +func (c *CommandNode) tree() *Tree { + return c.tr +} + +func (c *CommandNode) Copy() Node { + if c == nil { + return c + } + n := c.tr.newCommand(c.Pos) + for _, c := range c.Args { + n.append(c.Copy()) + } + return n +} + +// IdentifierNode holds an identifier. +type IdentifierNode struct { + NodeType + Pos + tr *Tree + Ident string // The identifier's name. +} + +// NewIdentifier returns a new IdentifierNode with the given identifier name. +func NewIdentifier(ident string) *IdentifierNode { + return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident} +} + +// SetPos sets the position. NewIdentifier is a public method so we can't modify its signature. +// Chained for convenience. +// TODO: fix one day? +func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode { + i.Pos = pos + return i +} + +// SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature. +// Chained for convenience. +// TODO: fix one day? +func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode { + i.tr = t + return i +} + +func (i *IdentifierNode) String() string { + return i.Ident +} + +func (i *IdentifierNode) writeTo(sb *strings.Builder) { + sb.WriteString(i.String()) +} + +func (i *IdentifierNode) tree() *Tree { + return i.tr +} + +func (i *IdentifierNode) Copy() Node { + return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos) +} + +// VariableNode holds a list of variable names, possibly with chained field +// accesses. The dollar sign is part of the (first) name. +type VariableNode struct { + NodeType + Pos + tr *Tree + Ident []string // Variable name and fields in lexical order. +} + +func (t *Tree) newVariable(pos Pos, ident string) *VariableNode { + return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")} +} + +func (v *VariableNode) String() string { + var sb strings.Builder + v.writeTo(&sb) + return sb.String() +} + +func (v *VariableNode) writeTo(sb *strings.Builder) { + for i, id := range v.Ident { + if i > 0 { + sb.WriteByte('.') + } + sb.WriteString(id) + } +} + +func (v *VariableNode) tree() *Tree { + return v.tr +} + +func (v *VariableNode) Copy() Node { + return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)} +} + +// DotNode holds the special identifier '.'. +type DotNode struct { + NodeType + Pos + tr *Tree +} + +func (t *Tree) newDot(pos Pos) *DotNode { + return &DotNode{tr: t, NodeType: NodeDot, Pos: pos} +} + +func (d *DotNode) Type() NodeType { + // Override method on embedded NodeType for API compatibility. + // TODO: Not really a problem; could change API without effect but + // api tool complains. + return NodeDot +} + +func (d *DotNode) String() string { + return "." +} + +func (d *DotNode) writeTo(sb *strings.Builder) { + sb.WriteString(d.String()) +} + +func (d *DotNode) tree() *Tree { + return d.tr +} + +func (d *DotNode) Copy() Node { + return d.tr.newDot(d.Pos) +} + +// NilNode holds the special identifier 'nil' representing an untyped nil constant. +type NilNode struct { + NodeType + Pos + tr *Tree +} + +func (t *Tree) newNil(pos Pos) *NilNode { + return &NilNode{tr: t, NodeType: NodeNil, Pos: pos} +} + +func (n *NilNode) Type() NodeType { + // Override method on embedded NodeType for API compatibility. + // TODO: Not really a problem; could change API without effect but + // api tool complains. + return NodeNil +} + +func (n *NilNode) String() string { + return "nil" +} + +func (n *NilNode) writeTo(sb *strings.Builder) { + sb.WriteString(n.String()) +} + +func (n *NilNode) tree() *Tree { + return n.tr +} + +func (n *NilNode) Copy() Node { + return n.tr.newNil(n.Pos) +} + +// FieldNode holds a field (identifier starting with '.'). +// The names may be chained ('.x.y'). +// The period is dropped from each ident. +type FieldNode struct { + NodeType + Pos + tr *Tree + Ident []string // The identifiers in lexical order. +} + +func (t *Tree) newField(pos Pos, ident string) *FieldNode { + return &FieldNode{tr: t, NodeType: NodeField, Pos: pos, Ident: strings.Split(ident[1:], ".")} // [1:] to drop leading period +} + +func (f *FieldNode) String() string { + var sb strings.Builder + f.writeTo(&sb) + return sb.String() +} + +func (f *FieldNode) writeTo(sb *strings.Builder) { + for _, id := range f.Ident { + sb.WriteByte('.') + sb.WriteString(id) + } +} + +func (f *FieldNode) tree() *Tree { + return f.tr +} + +func (f *FieldNode) Copy() Node { + return &FieldNode{tr: f.tr, NodeType: NodeField, Pos: f.Pos, Ident: append([]string{}, f.Ident...)} +} + +// ChainNode holds a term followed by a chain of field accesses (identifier starting with '.'). +// The names may be chained ('.x.y'). +// The periods are dropped from each ident. +type ChainNode struct { + NodeType + Pos + tr *Tree + Node Node + Field []string // The identifiers in lexical order. +} + +func (t *Tree) newChain(pos Pos, node Node) *ChainNode { + return &ChainNode{tr: t, NodeType: NodeChain, Pos: pos, Node: node} +} + +// Add adds the named field (which should start with a period) to the end of the chain. +func (c *ChainNode) Add(field string) { + if len(field) == 0 || field[0] != '.' { + panic("no dot in field") + } + field = field[1:] // Remove leading dot. + if field == "" { + panic("empty field") + } + c.Field = append(c.Field, field) +} + +func (c *ChainNode) String() string { + var sb strings.Builder + c.writeTo(&sb) + return sb.String() +} + +func (c *ChainNode) writeTo(sb *strings.Builder) { + if _, ok := c.Node.(*PipeNode); ok { + sb.WriteByte('(') + c.Node.writeTo(sb) + sb.WriteByte(')') + } else { + c.Node.writeTo(sb) + } + for _, field := range c.Field { + sb.WriteByte('.') + sb.WriteString(field) + } +} + +func (c *ChainNode) tree() *Tree { + return c.tr +} + +func (c *ChainNode) Copy() Node { + return &ChainNode{tr: c.tr, NodeType: NodeChain, Pos: c.Pos, Node: c.Node, Field: append([]string{}, c.Field...)} +} + +// BoolNode holds a boolean constant. +type BoolNode struct { + NodeType + Pos + tr *Tree + True bool // The value of the boolean constant. +} + +func (t *Tree) newBool(pos Pos, true bool) *BoolNode { + return &BoolNode{tr: t, NodeType: NodeBool, Pos: pos, True: true} +} + +func (b *BoolNode) String() string { + if b.True { + return "true" + } + return "false" +} + +func (b *BoolNode) writeTo(sb *strings.Builder) { + sb.WriteString(b.String()) +} + +func (b *BoolNode) tree() *Tree { + return b.tr +} + +func (b *BoolNode) Copy() Node { + return b.tr.newBool(b.Pos, b.True) +} + +// NumberNode holds a number: signed or unsigned integer, float, or complex. +// The value is parsed and stored under all the types that can represent the value. +// This simulates in a small amount of code the behavior of Go's ideal constants. +type NumberNode struct { + NodeType + Pos + tr *Tree + IsInt bool // Number has an integral value. + IsUint bool // Number has an unsigned integral value. + IsFloat bool // Number has a floating-point value. + IsComplex bool // Number is complex. + Int64 int64 // The signed integer value. + Uint64 uint64 // The unsigned integer value. + Float64 float64 // The floating-point value. + Complex128 complex128 // The complex value. + Text string // The original textual representation from the input. +} + +func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error) { + n := &NumberNode{tr: t, NodeType: NodeNumber, Pos: pos, Text: text} + switch typ { + case itemCharConstant: + rune, _, tail, err := strconv.UnquoteChar(text[1:], text[0]) + if err != nil { + return nil, err + } + if tail != "'" { + return nil, fmt.Errorf("malformed character constant: %s", text) + } + n.Int64 = int64(rune) + n.IsInt = true + n.Uint64 = uint64(rune) + n.IsUint = true + n.Float64 = float64(rune) // odd but those are the rules. + n.IsFloat = true + return n, nil + case itemComplex: + // fmt.Sscan can parse the pair, so let it do the work. + if _, err := fmt.Sscan(text, &n.Complex128); err != nil { + return nil, err + } + n.IsComplex = true + n.simplifyComplex() + return n, nil + } + // Imaginary constants can only be complex unless they are zero. + if len(text) > 0 && text[len(text)-1] == 'i' { + f, err := strconv.ParseFloat(text[:len(text)-1], 64) + if err == nil { + n.IsComplex = true + n.Complex128 = complex(0, f) + n.simplifyComplex() + return n, nil + } + } + // Do integer test first so we get 0x123 etc. + u, err := strconv.ParseUint(text, 0, 64) // will fail for -0; fixed below. + if err == nil { + n.IsUint = true + n.Uint64 = u + } + i, err := strconv.ParseInt(text, 0, 64) + if err == nil { + n.IsInt = true + n.Int64 = i + if i == 0 { + n.IsUint = true // in case of -0. + n.Uint64 = u + } + } + // If an integer extraction succeeded, promote the float. + if n.IsInt { + n.IsFloat = true + n.Float64 = float64(n.Int64) + } else if n.IsUint { + n.IsFloat = true + n.Float64 = float64(n.Uint64) + } else { + f, err := strconv.ParseFloat(text, 64) + if err == nil { + // If we parsed it as a float but it looks like an integer, + // it's a huge number too large to fit in an int. Reject it. + if !strings.ContainsAny(text, ".eEpP") { + return nil, fmt.Errorf("integer overflow: %q", text) + } + n.IsFloat = true + n.Float64 = f + // If a floating-point extraction succeeded, extract the int if needed. + if !n.IsInt && float64(int64(f)) == f { + n.IsInt = true + n.Int64 = int64(f) + } + if !n.IsUint && float64(uint64(f)) == f { + n.IsUint = true + n.Uint64 = uint64(f) + } + } + } + if !n.IsInt && !n.IsUint && !n.IsFloat { + return nil, fmt.Errorf("illegal number syntax: %q", text) + } + return n, nil +} + +// simplifyComplex pulls out any other types that are represented by the complex number. +// These all require that the imaginary part be zero. +func (n *NumberNode) simplifyComplex() { + n.IsFloat = imag(n.Complex128) == 0 + if n.IsFloat { + n.Float64 = real(n.Complex128) + n.IsInt = float64(int64(n.Float64)) == n.Float64 + if n.IsInt { + n.Int64 = int64(n.Float64) + } + n.IsUint = float64(uint64(n.Float64)) == n.Float64 + if n.IsUint { + n.Uint64 = uint64(n.Float64) + } + } +} + +func (n *NumberNode) String() string { + return n.Text +} + +func (n *NumberNode) writeTo(sb *strings.Builder) { + sb.WriteString(n.String()) +} + +func (n *NumberNode) tree() *Tree { + return n.tr +} + +func (n *NumberNode) Copy() Node { + nn := new(NumberNode) + *nn = *n // Easy, fast, correct. + return nn +} + +// StringNode holds a string constant. The value has been "unquoted". +type StringNode struct { + NodeType + Pos + tr *Tree + Quoted string // The original text of the string, with quotes. + Text string // The string, after quote processing. +} + +func (t *Tree) newString(pos Pos, orig, text string) *StringNode { + return &StringNode{tr: t, NodeType: NodeString, Pos: pos, Quoted: orig, Text: text} +} + +func (s *StringNode) String() string { + return s.Quoted +} + +func (s *StringNode) writeTo(sb *strings.Builder) { + sb.WriteString(s.String()) +} + +func (s *StringNode) tree() *Tree { + return s.tr +} + +func (s *StringNode) Copy() Node { + return s.tr.newString(s.Pos, s.Quoted, s.Text) +} + +// endNode represents an {{end}} action. +// It does not appear in the final parse tree. +type endNode struct { + NodeType + Pos + tr *Tree +} + +func (t *Tree) newEnd(pos Pos) *endNode { + return &endNode{tr: t, NodeType: nodeEnd, Pos: pos} +} + +func (e *endNode) String() string { + return "{{end}}" +} + +func (e *endNode) writeTo(sb *strings.Builder) { + sb.WriteString(e.String()) +} + +func (e *endNode) tree() *Tree { + return e.tr +} + +func (e *endNode) Copy() Node { + return e.tr.newEnd(e.Pos) +} + +// elseNode represents an {{else}} action. Does not appear in the final tree. +type elseNode struct { + NodeType + Pos + tr *Tree + Line int // The line number in the input. Deprecated: Kept for compatibility. +} + +func (t *Tree) newElse(pos Pos, line int) *elseNode { + return &elseNode{tr: t, NodeType: nodeElse, Pos: pos, Line: line} +} + +func (e *elseNode) Type() NodeType { + return nodeElse +} + +func (e *elseNode) String() string { + return "{{else}}" +} + +func (e *elseNode) writeTo(sb *strings.Builder) { + sb.WriteString(e.String()) +} + +func (e *elseNode) tree() *Tree { + return e.tr +} + +func (e *elseNode) Copy() Node { + return e.tr.newElse(e.Pos, e.Line) +} + +// BranchNode is the common representation of if, range, and with. +type BranchNode struct { + NodeType + Pos + tr *Tree + Line int // The line number in the input. Deprecated: Kept for compatibility. + Pipe *PipeNode // The pipeline to be evaluated. + List *ListNode // What to execute if the value is non-empty. + ElseList *ListNode // What to execute if the value is empty (nil if absent). +} + +func (b *BranchNode) String() string { + var sb strings.Builder + b.writeTo(&sb) + return sb.String() +} + +func (b *BranchNode) writeTo(sb *strings.Builder) { + name := "" + switch b.NodeType { + case NodeIf: + name = "if" + case NodeRange: + name = "range" + case NodeWith: + name = "with" + default: + panic("unknown branch type") + } + sb.WriteString("{{") + sb.WriteString(name) + sb.WriteByte(' ') + b.Pipe.writeTo(sb) + sb.WriteString("}}") + b.List.writeTo(sb) + if b.ElseList != nil { + sb.WriteString("{{else}}") + b.ElseList.writeTo(sb) + } + sb.WriteString("{{end}}") +} + +func (b *BranchNode) tree() *Tree { + return b.tr +} + +func (b *BranchNode) Copy() Node { + switch b.NodeType { + case NodeIf: + return b.tr.newIf(b.Pos, b.Line, b.Pipe, b.List, b.ElseList) + case NodeRange: + return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList) + case NodeWith: + return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList) + default: + panic("unknown branch type") + } +} + +// IfNode represents an {{if}} action and its commands. +type IfNode struct { + BranchNode +} + +func (t *Tree) newIf(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *IfNode { + return &IfNode{BranchNode{tr: t, NodeType: NodeIf, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}} +} + +func (i *IfNode) Copy() Node { + return i.tr.newIf(i.Pos, i.Line, i.Pipe.CopyPipe(), i.List.CopyList(), i.ElseList.CopyList()) +} + +// RangeNode represents a {{range}} action and its commands. +type RangeNode struct { + BranchNode +} + +func (t *Tree) newRange(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *RangeNode { + return &RangeNode{BranchNode{tr: t, NodeType: NodeRange, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}} +} + +func (r *RangeNode) Copy() Node { + return r.tr.newRange(r.Pos, r.Line, r.Pipe.CopyPipe(), r.List.CopyList(), r.ElseList.CopyList()) +} + +// WithNode represents a {{with}} action and its commands. +type WithNode struct { + BranchNode +} + +func (t *Tree) newWith(pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) *WithNode { + return &WithNode{BranchNode{tr: t, NodeType: NodeWith, Pos: pos, Line: line, Pipe: pipe, List: list, ElseList: elseList}} +} + +func (w *WithNode) Copy() Node { + return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList()) +} + +// TemplateNode represents a {{template}} action. +type TemplateNode struct { + NodeType + Pos + tr *Tree + Line int // The line number in the input. Deprecated: Kept for compatibility. + Name string // The name of the template (unquoted). + Pipe *PipeNode // The command to evaluate as dot for the template. +} + +func (t *Tree) newTemplate(pos Pos, line int, name string, pipe *PipeNode) *TemplateNode { + return &TemplateNode{tr: t, NodeType: NodeTemplate, Pos: pos, Line: line, Name: name, Pipe: pipe} +} + +func (t *TemplateNode) String() string { + var sb strings.Builder + t.writeTo(&sb) + return sb.String() +} + +func (t *TemplateNode) writeTo(sb *strings.Builder) { + sb.WriteString("{{template ") + sb.WriteString(strconv.Quote(t.Name)) + if t.Pipe != nil { + sb.WriteByte(' ') + t.Pipe.writeTo(sb) + } + sb.WriteString("}}") +} + +func (t *TemplateNode) tree() *Tree { + return t.tr +} + +func (t *TemplateNode) Copy() Node { + return t.tr.newTemplate(t.Pos, t.Line, t.Name, t.Pipe.CopyPipe()) +} diff --git a/vendor/rsc.io/tmplfunc/internal/parse/parse.go b/vendor/rsc.io/tmplfunc/internal/parse/parse.go new file mode 100644 index 00000000000..1a63961c13e --- /dev/null +++ b/vendor/rsc.io/tmplfunc/internal/parse/parse.go @@ -0,0 +1,756 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package parse builds parse trees for templates as defined by text/template +// and html/template. Clients should use those packages to construct templates +// rather than this one, which provides shared internal data structures not +// intended for general use. +package parse + +import ( + "bytes" + "fmt" + "runtime" + "strconv" + "strings" +) + +// Tree is the representation of a single parsed template. +type Tree struct { + Name string // name of the template represented by the tree. + ParseName string // name of the top-level template during parsing, for error messages. + Root *ListNode // top-level root of the tree. + Mode Mode // parsing mode. + text string // text parsed to create the template (or its parent) + // Parsing only; cleared after parse. + funcs []map[string]interface{} + lex *lexer + token [3]item // three-token lookahead for parser. + peekCount int + vars []string // variables defined at the moment. + treeSet map[string]*Tree + actionLine int // line of left delim starting action + mode Mode +} + +// A mode value is a set of flags (or 0). Modes control parser behavior. +type Mode uint + +const ( + ParseComments Mode = 1 << iota // parse comments and add them to AST + SkipFuncCheck // do not check that functions are defined +) + +// Copy returns a copy of the Tree. Any parsing state is discarded. +func (t *Tree) Copy() *Tree { + if t == nil { + return nil + } + return &Tree{ + Name: t.Name, + ParseName: t.ParseName, + Root: t.Root.CopyList(), + text: t.text, + } +} + +// Parse returns a map from template name to parse.Tree, created by parsing the +// templates described in the argument string. The top-level template will be +// given the specified name. If an error is encountered, parsing stops and an +// empty map is returned with the error. +func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (map[string]*Tree, error) { + treeSet := make(map[string]*Tree) + t := New(name) + t.text = text + _, err := t.Parse(text, leftDelim, rightDelim, treeSet, funcs...) + return treeSet, err +} + +// next returns the next token. +func (t *Tree) next() item { + if t.peekCount > 0 { + t.peekCount-- + } else { + t.token[0] = t.lex.nextItem() + } + return t.token[t.peekCount] +} + +// backup backs the input stream up one token. +func (t *Tree) backup() { + t.peekCount++ +} + +// backup2 backs the input stream up two tokens. +// The zeroth token is already there. +func (t *Tree) backup2(t1 item) { + t.token[1] = t1 + t.peekCount = 2 +} + +// backup3 backs the input stream up three tokens +// The zeroth token is already there. +func (t *Tree) backup3(t2, t1 item) { // Reverse order: we're pushing back. + t.token[1] = t1 + t.token[2] = t2 + t.peekCount = 3 +} + +// peek returns but does not consume the next token. +func (t *Tree) peek() item { + if t.peekCount > 0 { + return t.token[t.peekCount-1] + } + t.peekCount = 1 + t.token[0] = t.lex.nextItem() + return t.token[0] +} + +// nextNonSpace returns the next non-space token. +func (t *Tree) nextNonSpace() (token item) { + for { + token = t.next() + if token.typ != itemSpace { + break + } + } + return token +} + +// peekNonSpace returns but does not consume the next non-space token. +func (t *Tree) peekNonSpace() item { + token := t.nextNonSpace() + t.backup() + return token +} + +// Parsing. + +// New allocates a new parse tree with the given name. +func New(name string, funcs ...map[string]interface{}) *Tree { + return &Tree{ + Name: name, + funcs: funcs, + } +} + +// ErrorContext returns a textual representation of the location of the node in the input text. +// The receiver is only used when the node does not have a pointer to the tree inside, +// which can occur in old code. +func (t *Tree) ErrorContext(n Node) (location, context string) { + pos := int(n.Position()) + tree := n.tree() + if tree == nil { + tree = t + } + text := tree.text[:pos] + byteNum := strings.LastIndex(text, "\n") + if byteNum == -1 { + byteNum = pos // On first line. + } else { + byteNum++ // After the newline. + byteNum = pos - byteNum + } + lineNum := 1 + strings.Count(text, "\n") + context = n.String() + return fmt.Sprintf("%s:%d:%d", tree.ParseName, lineNum, byteNum), context +} + +// errorf formats the error and terminates processing. +func (t *Tree) errorf(format string, args ...interface{}) { + t.Root = nil + format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format) + panic(fmt.Errorf(format, args...)) +} + +// error terminates processing. +func (t *Tree) error(err error) { + t.errorf("%s", err) +} + +// expect consumes the next token and guarantees it has the required type. +func (t *Tree) expect(expected itemType, context string) item { + token := t.nextNonSpace() + if token.typ != expected { + t.unexpected(token, context) + } + return token +} + +// expectOneOf consumes the next token and guarantees it has one of the required types. +func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { + token := t.nextNonSpace() + if token.typ != expected1 && token.typ != expected2 { + t.unexpected(token, context) + } + return token +} + +// unexpected complains about the token and terminates processing. +func (t *Tree) unexpected(token item, context string) { + if token.typ == itemError { + extra := "" + if t.actionLine != 0 && t.actionLine != token.line { + extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine) + if strings.HasSuffix(token.val, " action") { + extra = extra[len(" in action"):] // avoid "action in action" + } + } + t.errorf("%s%s", token, extra) + } + t.errorf("unexpected %s in %s", token, context) +} + +// recover is the handler that turns panics into returns from the top level of Parse. +func (t *Tree) recover(errp *error) { + e := recover() + if e != nil { + if _, ok := e.(runtime.Error); ok { + panic(e) + } + if t != nil { + t.lex.drain() + t.stopParse() + } + *errp = e.(error) + } +} + +// startParse initializes the parser, using the lexer. +func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet map[string]*Tree) { + t.Root = nil + t.lex = lex + t.vars = []string{"$"} + t.funcs = funcs + t.treeSet = treeSet +} + +// stopParse terminates parsing. +func (t *Tree) stopParse() { + t.lex = nil + t.vars = nil + t.funcs = nil + t.treeSet = nil +} + +// Parse parses the template definition string to construct a representation of +// the template for execution. If either action delimiter string is empty, the +// default ("{{" or "}}") is used. Embedded template definitions are added to +// the treeSet map. +func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) { + defer t.recover(&err) + t.ParseName = t.Name + emitComment := t.Mode&ParseComments != 0 + t.startParse(funcs, lex(t.Name, text, leftDelim, rightDelim, emitComment), treeSet) + t.text = text + t.parse() + t.add() + t.stopParse() + return t, nil +} + +// add adds tree to t.treeSet. +func (t *Tree) add() { + tree := t.treeSet[t.Name] + if tree == nil || IsEmptyTree(tree.Root) { + t.treeSet[t.Name] = t + return + } + if !IsEmptyTree(t.Root) { + t.errorf("template: multiple definition of template %q", t.Name) + } +} + +// IsEmptyTree reports whether this tree (node) is empty of everything but space or comments. +func IsEmptyTree(n Node) bool { + switch n := n.(type) { + case nil: + return true + case *ActionNode: + case *CommentNode: + return true + case *IfNode: + case *ListNode: + for _, node := range n.Nodes { + if !IsEmptyTree(node) { + return false + } + } + return true + case *RangeNode: + case *TemplateNode: + case *TextNode: + return len(bytes.TrimSpace(n.Text)) == 0 + case *WithNode: + default: + panic("unknown node: " + n.String()) + } + return false +} + +// parse is the top-level parser for a template, essentially the same +// as itemList except it also parses {{define}} actions. +// It runs to EOF. +func (t *Tree) parse() { + t.Root = t.newList(t.peek().pos) + for t.peek().typ != itemEOF { + if t.peek().typ == itemLeftDelim { + delim := t.next() + if t.nextNonSpace().typ == itemDefine { + newT := New("definition") // name will be updated once we know it. + newT.text = t.text + newT.Mode = t.Mode + newT.ParseName = t.ParseName + newT.startParse(t.funcs, t.lex, t.treeSet) + newT.parseDefinition() + continue + } + t.backup2(delim) + } + switch n := t.textOrAction(); n.Type() { + case nodeEnd, nodeElse: + t.errorf("unexpected %s", n) + default: + t.Root.append(n) + } + } +} + +// parseDefinition parses a {{define}} ... {{end}} template definition and +// installs the definition in t.treeSet. The "define" keyword has already +// been scanned. +func (t *Tree) parseDefinition() { + const context = "define clause" + name := t.expectOneOf(itemString, itemRawString, context) + var err error + t.Name, err = strconv.Unquote(name.val) + if err != nil { + t.error(err) + } + t.expect(itemRightDelim, context) + var end Node + t.Root, end = t.itemList() + if end.Type() != nodeEnd { + t.errorf("unexpected %s in %s", end, context) + } + t.add() + t.stopParse() +} + +// itemList: +// textOrAction* +// Terminates at {{end}} or {{else}}, returned separately. +func (t *Tree) itemList() (list *ListNode, next Node) { + list = t.newList(t.peekNonSpace().pos) + for t.peekNonSpace().typ != itemEOF { + n := t.textOrAction() + switch n.Type() { + case nodeEnd, nodeElse: + return list, n + } + list.append(n) + } + t.errorf("unexpected EOF") + return +} + +// textOrAction: +// text | comment | action +func (t *Tree) textOrAction() Node { + switch token := t.nextNonSpace(); token.typ { + case itemText: + return t.newText(token.pos, token.val) + case itemLeftDelim: + t.actionLine = token.line + defer t.clearActionLine() + return t.action() + case itemComment: + return t.newComment(token.pos, token.val) + default: + t.unexpected(token, "input") + } + return nil +} + +func (t *Tree) clearActionLine() { + t.actionLine = 0 +} + +// Action: +// control +// command ("|" command)* +// Left delim is past. Now get actions. +// First word could be a keyword such as range. +func (t *Tree) action() (n Node) { + switch token := t.nextNonSpace(); token.typ { + case itemBlock: + return t.blockControl() + case itemElse: + return t.elseControl() + case itemEnd: + return t.endControl() + case itemIf: + return t.ifControl() + case itemRange: + return t.rangeControl() + case itemTemplate: + return t.templateControl() + case itemWith: + return t.withControl() + } + t.backup() + token := t.peek() + // Do not pop variables; they persist until "end". + return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) +} + +// Pipeline: +// declarations? command ('|' command)* +func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { + token := t.peekNonSpace() + pipe = t.newPipeline(token.pos, token.line, nil) + // Are there declarations or assignments? +decls: + if v := t.peekNonSpace(); v.typ == itemVariable { + t.next() + // Since space is a token, we need 3-token look-ahead here in the worst case: + // in "$x foo" we need to read "foo" (as opposed to ":=") to know that $x is an + // argument variable rather than a declaration. So remember the token + // adjacent to the variable so we can push it back if necessary. + tokenAfterVariable := t.peek() + next := t.peekNonSpace() + switch { + case next.typ == itemAssign, next.typ == itemDeclare: + pipe.IsAssign = next.typ == itemAssign + t.nextNonSpace() + pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val)) + t.vars = append(t.vars, v.val) + case next.typ == itemChar && next.val == ",": + t.nextNonSpace() + pipe.Decl = append(pipe.Decl, t.newVariable(v.pos, v.val)) + t.vars = append(t.vars, v.val) + if context == "range" && len(pipe.Decl) < 2 { + switch t.peekNonSpace().typ { + case itemVariable, itemRightDelim, itemRightParen: + // second initialized variable in a range pipeline + goto decls + default: + t.errorf("range can only initialize variables") + } + } + t.errorf("too many declarations in %s", context) + case tokenAfterVariable.typ == itemSpace: + t.backup3(v, tokenAfterVariable) + default: + t.backup2(v) + } + } + for { + switch token := t.nextNonSpace(); token.typ { + case end: + // At this point, the pipeline is complete + t.checkPipeline(pipe, context) + return + case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, + itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: + t.backup() + pipe.append(t.command()) + default: + t.unexpected(token, context) + } + } +} + +func (t *Tree) checkPipeline(pipe *PipeNode, context string) { + // Reject empty pipelines + if len(pipe.Cmds) == 0 { + t.errorf("missing value for %s", context) + } + // Only the first command of a pipeline can start with a non executable operand + for i, c := range pipe.Cmds[1:] { + switch c.Args[0].Type() { + case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString: + // With A|B|C, pipeline stage 2 is B + t.errorf("non executable command in pipeline stage %d", i+2) + } + } +} + +func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { + defer t.popVars(len(t.vars)) + pipe = t.pipeline(context, itemRightDelim) + var next Node + list, next = t.itemList() + switch next.Type() { + case nodeEnd: //done + case nodeElse: + if allowElseIf { + // Special case for "else if". If the "else" is followed immediately by an "if", + // the elseControl will have left the "if" token pending. Treat + // {{if a}}_{{else if b}}_{{end}} + // as + // {{if a}}_{{else}}{{if b}}_{{end}}{{end}}. + // To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}} + // is assumed. This technique works even for long if-else-if chains. + // TODO: Should we allow else-if in with and range? + if t.peek().typ == itemIf { + t.next() // Consume the "if" token. + elseList = t.newList(next.Position()) + elseList.append(t.ifControl()) + // Do not consume the next item - only one {{end}} required. + break + } + } + elseList, next = t.itemList() + if next.Type() != nodeEnd { + t.errorf("expected end; found %s", next) + } + } + return pipe.Position(), pipe.Line, pipe, list, elseList +} + +// If: +// {{if pipeline}} itemList {{end}} +// {{if pipeline}} itemList {{else}} itemList {{end}} +// If keyword is past. +func (t *Tree) ifControl() Node { + return t.newIf(t.parseControl(true, "if")) +} + +// Range: +// {{range pipeline}} itemList {{end}} +// {{range pipeline}} itemList {{else}} itemList {{end}} +// Range keyword is past. +func (t *Tree) rangeControl() Node { + return t.newRange(t.parseControl(false, "range")) +} + +// With: +// {{with pipeline}} itemList {{end}} +// {{with pipeline}} itemList {{else}} itemList {{end}} +// If keyword is past. +func (t *Tree) withControl() Node { + return t.newWith(t.parseControl(false, "with")) +} + +// End: +// {{end}} +// End keyword is past. +func (t *Tree) endControl() Node { + return t.newEnd(t.expect(itemRightDelim, "end").pos) +} + +// Else: +// {{else}} +// Else keyword is past. +func (t *Tree) elseControl() Node { + // Special case for "else if". + peek := t.peekNonSpace() + if peek.typ == itemIf { + // We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ". + return t.newElse(peek.pos, peek.line) + } + token := t.expect(itemRightDelim, "else") + return t.newElse(token.pos, token.line) +} + +// Block: +// {{block stringValue pipeline}} +// Block keyword is past. +// The name must be something that can evaluate to a string. +// The pipeline is mandatory. +func (t *Tree) blockControl() Node { + const context = "block clause" + + token := t.nextNonSpace() + name := t.parseTemplateName(token, context) + pipe := t.pipeline(context, itemRightDelim) + + block := New(name) // name will be updated once we know it. + block.text = t.text + block.Mode = t.Mode + block.ParseName = t.ParseName + block.startParse(t.funcs, t.lex, t.treeSet) + var end Node + block.Root, end = block.itemList() + if end.Type() != nodeEnd { + t.errorf("unexpected %s in %s", end, context) + } + block.add() + block.stopParse() + + return t.newTemplate(token.pos, token.line, name, pipe) +} + +// Template: +// {{template stringValue pipeline}} +// Template keyword is past. The name must be something that can evaluate +// to a string. +func (t *Tree) templateControl() Node { + const context = "template clause" + token := t.nextNonSpace() + name := t.parseTemplateName(token, context) + var pipe *PipeNode + if t.nextNonSpace().typ != itemRightDelim { + t.backup() + // Do not pop variables; they persist until "end". + pipe = t.pipeline(context, itemRightDelim) + } + return t.newTemplate(token.pos, token.line, name, pipe) +} + +func (t *Tree) parseTemplateName(token item, context string) (name string) { + switch token.typ { + case itemString, itemRawString: + s, err := strconv.Unquote(token.val) + if err != nil { + t.error(err) + } + name = s + default: + t.unexpected(token, context) + } + return +} + +// command: +// operand (space operand)* +// space-separated arguments up to a pipeline character or right delimiter. +// we consume the pipe character but leave the right delim to terminate the action. +func (t *Tree) command() *CommandNode { + cmd := t.newCommand(t.peekNonSpace().pos) + for { + t.peekNonSpace() // skip leading spaces. + operand := t.operand() + if operand != nil { + cmd.append(operand) + } + switch token := t.next(); token.typ { + case itemSpace: + continue + case itemRightDelim, itemRightParen: + t.backup() + case itemPipe: + // nothing here; break loop below + default: + t.unexpected(token, "operand") + } + break + } + if len(cmd.Args) == 0 { + t.errorf("empty command") + } + return cmd +} + +// operand: +// term .Field* +// An operand is a space-separated component of a command, +// a term possibly followed by field accesses. +// A nil return means the next item is not an operand. +func (t *Tree) operand() Node { + node := t.term() + if node == nil { + return nil + } + if t.peek().typ == itemField { + chain := t.newChain(t.peek().pos, node) + for t.peek().typ == itemField { + chain.Add(t.next().val) + } + // Compatibility with original API: If the term is of type NodeField + // or NodeVariable, just put more fields on the original. + // Otherwise, keep the Chain node. + // Obvious parsing errors involving literal values are detected here. + // More complex error cases will have to be handled at execution time. + switch node.Type() { + case NodeField: + node = t.newField(chain.Position(), chain.String()) + case NodeVariable: + node = t.newVariable(chain.Position(), chain.String()) + case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot: + t.errorf("unexpected . after term %q", node.String()) + default: + node = chain + } + } + return node +} + +// term: +// literal (number, string, nil, boolean) +// function (identifier) +// . +// .Field +// $ +// '(' pipeline ')' +// A term is a simple "expression". +// A nil return means the next item is not a term. +func (t *Tree) term() Node { + switch token := t.nextNonSpace(); token.typ { + case itemIdentifier: + checkFunc := t.Mode&SkipFuncCheck == 0 + if checkFunc && !t.hasFunction(token.val) { + t.errorf("function %q not defined", token.val) + } + return NewIdentifier(token.val).SetTree(t).SetPos(token.pos) + case itemDot: + return t.newDot(token.pos) + case itemNil: + return t.newNil(token.pos) + case itemVariable: + return t.useVar(token.pos, token.val) + case itemField: + return t.newField(token.pos, token.val) + case itemBool: + return t.newBool(token.pos, token.val == "true") + case itemCharConstant, itemComplex, itemNumber: + number, err := t.newNumber(token.pos, token.val, token.typ) + if err != nil { + t.error(err) + } + return number + case itemLeftParen: + return t.pipeline("parenthesized pipeline", itemRightParen) + case itemString, itemRawString: + s, err := strconv.Unquote(token.val) + if err != nil { + t.error(err) + } + return t.newString(token.pos, token.val, s) + } + t.backup() + return nil +} + +// hasFunction reports if a function name exists in the Tree's maps. +func (t *Tree) hasFunction(name string) bool { + for _, funcMap := range t.funcs { + if funcMap == nil { + continue + } + if funcMap[name] != nil { + return true + } + } + return false +} + +// popVars trims the variable list to the specified length +func (t *Tree) popVars(n int) { + t.vars = t.vars[:n] +} + +// useVar returns a node for a variable reference. It errors if the +// variable is not defined. +func (t *Tree) useVar(pos Pos, name string) Node { + v := t.newVariable(pos, name) + for _, varName := range t.vars { + if varName == v.Ident[0] { + return v + } + } + t.errorf("undefined variable %q", v.Ident[0]) + return nil +} diff --git a/vendor/rsc.io/tmplfunc/tmpl.go b/vendor/rsc.io/tmplfunc/tmpl.go new file mode 100644 index 00000000000..a10cbc53b70 --- /dev/null +++ b/vendor/rsc.io/tmplfunc/tmpl.go @@ -0,0 +1,213 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package tmplfunc provides an extension of Go templates +// in which templates can be invoked as if they were functions. +// +// For example, after parsing +// +// {{define "link url text"}}{{.text}}{{end}} +// +// this package installs a function named link allowing the template +// to be invoked as +// +// {{link "https://golang.org" "the Go language"}} +// +// instead of the longer-form (assuming an appropriate function named dict) +// +// {{template "link" (dict "url" "https://golang.org" "text" "the Go language")}} +// +// Function Definitions +// +// The function installed for a given template depends on the name of the +// defined template, which can include not just a function name but also +// a list of parameter names. The function name and parameter names must +// consist only of letters, digits, and underscores, with a leading non-digit. +// +// If there is no parameter list, then the function is expected to take +// at most one argument, made available in the template body as “.” (dot). +// If such a function is called with no arguments, dot will be a nil interface value. +// +// If there is a parameter list, then the function requires an argument for +// each parameter, except for optional and variadic parameters, explained below. +// Inside the template, the top-level value “.” is a map[string]interface{} in which +// each parameter name is mapped to the corresponding argument value. +// A parameter x can therefore be accessed as {{(index . "x")}} or, more concisely, {{.x}}. +// +// The first special case in parameter handling is that +// a parameter can be made optional by adding a “?” suffix after its name. +// If the argument list ends before that parameter, the corresponding map entry +// will be present and set to a nil value. +// The second special case is that a parameter can be made variadic +// by adding a “...” suffix after its name. +// The corresponding map entry contains a []interface{} holding the +// zero or more arguments corresponding to that parameter. +// +// In the parameter list, required parameters must precede optional parameters, +// which must in turn precede any variadic parameter. +// +// For example, we can revise the link template given earlier to make the +// link text optional, substituting the URL when the text is omitted: +// +// {{define "link url text?"}}{{or .text .url}}{{end}} +// +// The Go home page is {{link "https://golang.org"}}. +// +// Usage +// +// This package is meant to be used with templates from either the +// text/template or html/template packages. Given a *template.Template +// variable t, substitute: +// +// t.Parse(text) -> tmplfunc.Parse(t, text) +// t.ParseFiles(list) -> tmplfunc.ParseFiles(t, list) +// t.ParseGlob(pattern) -> tmplfunc.ParseGlob(t, pattern) +// +// Parse, ParseFiles, and ParseGlob parse the new templates but also add +// functions that invoke them, named according to the function signatures. +// Templates can only invoke functions for templates that have already been +// defined or that are being defined in the same Parse, ParseFiles, or ParseGlob call. +// For example, templates in two files x.tmpl and y.tmpl can call each other +// only if ParseFiles or ParseGlob is used to parse both files in a single call. +// Otherwise, the parsing of the first file will report that calls to templates in +// the second file are calling unknown functions. +// +// When used with the html/template package, all function-invoked template +// calls are treated as invoking templates producing HTML. In order to use a +// template that produces some other kind of text fragment, the template must +// be invoked directly using the {{template "name"}} form, not as a function call. +package tmplfunc + +import ( + "fmt" + "io/ioutil" + "path/filepath" + + htmltemplate "html/template" + texttemplate "text/template" +) + +// A Template is a *template.Template, where template refers to either +// the html/template or text/template package. +type Template interface { + // Method here only to make most types that are not a *template.Template + // not implement the interface. The requirement here is to be one of the two + // template types, not just to have this single method. + DefinedTemplates() string + Name() string +} + +// Parse is like t.Parse(text), adding functions for the templates defined in text. +func Parse(t Template, text string) error { + if err := funcs(t, []string{t.Name()}, []string{text}); err != nil { + return err + } + var err error + switch t := t.(type) { + case *texttemplate.Template: + _, err = t.Parse(text) + case *htmltemplate.Template: + _, err = t.Parse(text) + } + return err +} + +// ParseFiles is like t.ParseFiles(filenames...), adding functions for the parsed templates. +func ParseFiles(t Template, filenames ...string) error { + return parseFiles(t, readFileOS, filenames...) +} + +// parseFiles is the helper for the method and function. If the argument +// template is nil, it is created from the first file. +func parseFiles(t Template, readFile func(string) (string, []byte, error), filenames ...string) error { + if len(filenames) == 0 { + // Not really a problem, but be consistent. + return fmt.Errorf("tmplfunc: no files named in call to ParseFiles") + } + + var names []string + var texts []string + for _, filename := range filenames { + name, b, err := readFile(filename) + if err != nil { + return err + } + names = append(names, name) + texts = append(texts, string(b)) + } + + err := funcs(t, names, texts) + if err != nil { + return err + } + + switch t := t.(type) { + case *texttemplate.Template: + for i, name := range names { + var tmpl *texttemplate.Template + if name == t.Name() { + tmpl = t + } else { + tmpl = t.New(name) + } + if _, err := tmpl.Parse(texts[i]); err != nil { + return err + } + } + + case *htmltemplate.Template: + for i, name := range names { + var tmpl *htmltemplate.Template + if name == t.Name() { + tmpl = t + } else { + tmpl = t.New(name) + } + if _, err := tmpl.Parse(texts[i]); err != nil { + return err + } + } + } + + return nil +} + +// ParseGlob is like t.ParseGlob(pattern), adding functions for the parsed templates. +func ParseGlob(t Template, pattern string) error { + filenames, err := filepath.Glob(pattern) + if err != nil { + return err + } + if len(filenames) == 0 { + return fmt.Errorf("tmplfunc: pattern matches no files: %#q", pattern) + } + return parseFiles(t, readFileOS, filenames...) +} + +func must(err error) { + if err != nil { + panic(err) + } +} + +// MustParse is like Parse but panics on error. +func MustParse(t Template, text string) { + must(Parse(t, text)) +} + +// MustParseFiles is like ParseFiles but panics on error. +func MustParseFiles(t Template, filenames ...string) { + must(ParseFiles(t, filenames...)) +} + +// MustParseGlob is like ParseGlob but panics on error. +func MustParseGlob(t Template, pattern string) { + must(ParseGlob(t, pattern)) +} + +func readFileOS(file string) (name string, b []byte, err error) { + name = filepath.Base(file) + b, err = ioutil.ReadFile(file) + return +}