From 71d606ae7f32f71b432df502b12e2361bf7dc7e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 Oct 2023 21:10:51 +0000 Subject: [PATCH] Bump github.com/consensys/gnark-crypto from 0.9.1 to 0.12.0 Bumps [github.com/consensys/gnark-crypto](https://github.com/consensys/gnark-crypto) from 0.9.1 to 0.12.0. - [Release notes](https://github.com/consensys/gnark-crypto/releases) - [Changelog](https://github.com/Consensys/gnark-crypto/blob/master/CHANGELOG.md) - [Commits](https://github.com/consensys/gnark-crypto/compare/v0.9.1...v0.12.0) --- updated-dependencies: - dependency-name: github.com/consensys/gnark-crypto dependency-type: indirect ... Signed-off-by: dependabot[bot] --- go.mod | 16 +- go.sum | 38 +- .../bits-and-blooms/bitset/.gitignore | 26 + .../bits-and-blooms/bitset/.travis.yml | 37 + .../github.com/bits-and-blooms/bitset/LICENSE | 27 + .../bits-and-blooms/bitset/README.md | 137 +++ .../bitset/azure-pipelines.yml | 39 + .../bits-and-blooms/bitset/bitset.go | 1036 +++++++++++++++++ .../bits-and-blooms/bitset/popcnt.go | 53 + .../bits-and-blooms/bitset/popcnt_19.go | 46 + .../bits-and-blooms/bitset/popcnt_amd64.go | 68 ++ .../bits-and-blooms/bitset/popcnt_amd64.s | 104 ++ .../bits-and-blooms/bitset/popcnt_generic.go | 25 + .../bitset/trailing_zeros_18.go | 15 + .../bitset/trailing_zeros_19.go | 10 + .../gnark-crypto/ecc/bls12-377/bls12-377.go | 10 +- .../gnark-crypto/ecc/bls12-377/fp/element.go | 16 +- .../gnark-crypto/ecc/bls12-377/fp/vector.go | 123 ++ .../gnark-crypto/ecc/bls12-377/fr/element.go | 16 +- .../gnark-crypto/ecc/bls12-377/fr/vector.go | 121 ++ .../gnark-crypto/ecc/bls12-377/g1.go | 18 +- .../gnark-crypto/ecc/bls12-377/g2.go | 18 +- .../gnark-crypto/ecc/bls12-377/hash_to_g1.go | 14 +- .../gnark-crypto/ecc/bls12-377/hash_to_g2.go | 14 +- .../ecc/bls12-377/internal/fptower/asm.go | 2 +- .../bls12-377/internal/fptower/asm_noadx.go | 2 +- .../ecc/bls12-377/internal/fptower/e12.go | 38 +- .../bls12-377/internal/fptower/e12_pairing.go | 50 + .../ecc/bls12-377/internal/fptower/e2.go | 4 +- .../bls12-377/internal/fptower/e2_amd64.go | 2 +- .../bls12-377/internal/fptower/e2_fallback.go | 2 +- .../ecc/bls12-377/internal/fptower/e6.go | 32 +- .../gnark-crypto/ecc/bls12-377/marshal.go | 244 +++- .../gnark-crypto/ecc/bls12-377/multiexp.go | 209 +++- .../ecc/bls12-377/multiexp_affine.go | 38 +- .../ecc/bls12-377/multiexp_jacobian.go | 38 +- .../gnark-crypto/ecc/bls12-377/pairing.go | 148 ++- .../gnark-crypto/ecc/bls12-381/bls12-381.go | 19 +- .../gnark-crypto/ecc/bls12-381/fp/element.go | 16 +- .../gnark-crypto/ecc/bls12-381/fp/vector.go | 123 ++ .../gnark-crypto/ecc/bls12-381/fr/element.go | 16 +- .../gnark-crypto/ecc/bls12-381/fr/vector.go | 121 ++ .../gnark-crypto/ecc/bls12-381/g1.go | 18 +- .../gnark-crypto/ecc/bls12-381/g2.go | 18 +- .../gnark-crypto/ecc/bls12-381/hash_to_g1.go | 14 +- .../gnark-crypto/ecc/bls12-381/hash_to_g2.go | 14 +- .../ecc/bls12-381/internal/fptower/asm.go | 2 +- .../bls12-381/internal/fptower/asm_noadx.go | 2 +- .../ecc/bls12-381/internal/fptower/e12.go | 38 +- .../bls12-381/internal/fptower/e12_pairing.go | 35 +- .../ecc/bls12-381/internal/fptower/e2.go | 4 +- .../bls12-381/internal/fptower/e2_amd64.go | 2 +- .../bls12-381/internal/fptower/e2_fallback.go | 2 +- .../ecc/bls12-381/internal/fptower/e6.go | 32 +- .../gnark-crypto/ecc/bls12-381/marshal.go | 244 +++- .../gnark-crypto/ecc/bls12-381/multiexp.go | 209 +++- .../ecc/bls12-381/multiexp_affine.go | 38 +- .../ecc/bls12-381/multiexp_jacobian.go | 38 +- .../gnark-crypto/ecc/bls12-381/pairing.go | 127 +- .../consensys/gnark-crypto/ecc/bn254/bn254.go | 21 +- .../gnark-crypto/ecc/bn254/fp/element.go | 16 +- .../gnark-crypto/ecc/bn254/fp/vector.go | 121 ++ .../gnark-crypto/ecc/bn254/fr/element.go | 16 +- .../gnark-crypto/ecc/bn254/fr/vector.go | 121 ++ .../consensys/gnark-crypto/ecc/bn254/g1.go | 18 +- .../consensys/gnark-crypto/ecc/bn254/g2.go | 18 +- .../gnark-crypto/ecc/bn254/hash_to_g1.go | 14 +- .../gnark-crypto/ecc/bn254/hash_to_g2.go | 14 +- .../ecc/bn254/internal/fptower/asm.go | 2 +- .../ecc/bn254/internal/fptower/asm_noadx.go | 2 +- .../ecc/bn254/internal/fptower/e12.go | 36 +- .../ecc/bn254/internal/fptower/e12_pairing.go | 35 +- .../ecc/bn254/internal/fptower/e2.go | 4 +- .../ecc/bn254/internal/fptower/e2_amd64.go | 2 +- .../ecc/bn254/internal/fptower/e2_fallback.go | 2 +- .../ecc/bn254/internal/fptower/e6.go | 32 +- .../gnark-crypto/ecc/bn254/marshal.go | 187 ++- .../gnark-crypto/ecc/bn254/multiexp.go | 209 +++- .../gnark-crypto/ecc/bn254/multiexp_affine.go | 38 +- .../ecc/bn254/multiexp_jacobian.go | 38 +- .../gnark-crypto/ecc/bn254/pairing.go | 248 ++-- .../generator/internal/addchain/addchain.go | 2 +- .../gnark-crypto/internal/parallel/execute.go | 12 + vendor/github.com/stretchr/objx/Taskfile.yml | 2 +- .../stretchr/testify/assert/assertions.go | 78 +- .../github.com/stretchr/testify/mock/mock.go | 12 +- vendor/golang.org/x/crypto/bcrypt/bcrypt.go | 11 +- vendor/golang.org/x/crypto/cryptobyte/asn1.go | 87 +- .../golang.org/x/crypto/cryptobyte/builder.go | 9 +- .../x/crypto/pkcs12/internal/rc2/rc2.go | 53 +- vendor/golang.org/x/crypto/sha3/keccakf.go | 194 +-- vendor/golang.org/x/net/html/doc.go | 21 + vendor/golang.org/x/net/html/escape.go | 81 ++ vendor/golang.org/x/net/html/render.go | 2 +- vendor/golang.org/x/net/html/token.go | 10 +- vendor/golang.org/x/sys/cpu/endian_little.go | 4 +- vendor/golang.org/x/sys/cpu/hwcap_linux.go | 15 + vendor/golang.org/x/sys/cpu/runtime_auxv.go | 16 + .../x/sys/cpu/runtime_auxv_go121.go | 19 + vendor/golang.org/x/sys/unix/ioctl_signed.go | 70 ++ .../sys/unix/{ioctl.go => ioctl_unsigned.go} | 21 +- vendor/golang.org/x/sys/unix/ioctl_zos.go | 20 +- vendor/golang.org/x/sys/unix/mkall.sh | 2 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 11 +- vendor/golang.org/x/sys/unix/ptrace_darwin.go | 6 + vendor/golang.org/x/sys/unix/ptrace_ios.go | 6 + vendor/golang.org/x/sys/unix/syscall_aix.go | 7 +- .../golang.org/x/sys/unix/syscall_aix_ppc.go | 1 - .../x/sys/unix/syscall_aix_ppc64.go | 1 - vendor/golang.org/x/sys/unix/syscall_bsd.go | 3 +- .../golang.org/x/sys/unix/syscall_darwin.go | 15 +- .../x/sys/unix/syscall_darwin_amd64.go | 1 + .../x/sys/unix/syscall_darwin_arm64.go | 1 + .../x/sys/unix/syscall_dragonfly.go | 2 +- .../golang.org/x/sys/unix/syscall_freebsd.go | 44 +- .../x/sys/unix/syscall_freebsd_386.go | 17 +- .../x/sys/unix/syscall_freebsd_amd64.go | 17 +- .../x/sys/unix/syscall_freebsd_arm.go | 15 +- .../x/sys/unix/syscall_freebsd_arm64.go | 15 +- .../x/sys/unix/syscall_freebsd_riscv64.go | 15 +- vendor/golang.org/x/sys/unix/syscall_hurd.go | 8 + vendor/golang.org/x/sys/unix/syscall_linux.go | 72 +- .../x/sys/unix/syscall_linux_386.go | 27 - .../x/sys/unix/syscall_linux_amd64.go | 1 - .../x/sys/unix/syscall_linux_arm.go | 27 - .../x/sys/unix/syscall_linux_arm64.go | 10 - .../x/sys/unix/syscall_linux_loong64.go | 5 - .../x/sys/unix/syscall_linux_mips64x.go | 1 - .../x/sys/unix/syscall_linux_mipsx.go | 27 - .../x/sys/unix/syscall_linux_ppc.go | 27 - .../x/sys/unix/syscall_linux_ppc64x.go | 1 - .../x/sys/unix/syscall_linux_riscv64.go | 1 - .../x/sys/unix/syscall_linux_s390x.go | 1 - .../x/sys/unix/syscall_linux_sparc64.go | 1 - .../golang.org/x/sys/unix/syscall_netbsd.go | 7 +- .../golang.org/x/sys/unix/syscall_openbsd.go | 19 +- .../golang.org/x/sys/unix/syscall_solaris.go | 36 +- vendor/golang.org/x/sys/unix/syscall_unix.go | 7 + .../x/sys/unix/syscall_zos_s390x.go | 6 +- .../x/sys/unix/zerrors_darwin_amd64.go | 19 + .../x/sys/unix/zerrors_darwin_arm64.go | 19 + vendor/golang.org/x/sys/unix/zerrors_linux.go | 24 +- .../x/sys/unix/zerrors_linux_sparc64.go | 48 + .../x/sys/unix/zptrace_armnn_linux.go | 8 +- .../x/sys/unix/zptrace_linux_arm64.go | 4 +- .../x/sys/unix/zptrace_mipsnn_linux.go | 8 +- .../x/sys/unix/zptrace_mipsnnle_linux.go | 8 +- .../x/sys/unix/zptrace_x86_linux.go | 8 +- .../golang.org/x/sys/unix/zsyscall_aix_ppc.go | 23 +- .../x/sys/unix/zsyscall_aix_ppc64.go | 24 +- .../x/sys/unix/zsyscall_aix_ppc64_gc.go | 17 +- .../x/sys/unix/zsyscall_aix_ppc64_gccgo.go | 18 +- .../x/sys/unix/zsyscall_darwin_amd64.go | 55 +- .../x/sys/unix/zsyscall_darwin_amd64.s | 11 +- .../x/sys/unix/zsyscall_darwin_arm64.go | 55 +- .../x/sys/unix/zsyscall_darwin_arm64.s | 11 +- .../x/sys/unix/zsyscall_dragonfly_amd64.go | 20 +- .../x/sys/unix/zsyscall_freebsd_386.go | 30 +- .../x/sys/unix/zsyscall_freebsd_amd64.go | 30 +- .../x/sys/unix/zsyscall_freebsd_arm.go | 30 +- .../x/sys/unix/zsyscall_freebsd_arm64.go | 30 +- .../x/sys/unix/zsyscall_freebsd_riscv64.go | 30 +- .../golang.org/x/sys/unix/zsyscall_linux.go | 34 +- .../x/sys/unix/zsyscall_linux_386.go | 10 - .../x/sys/unix/zsyscall_linux_amd64.go | 10 - .../x/sys/unix/zsyscall_linux_arm.go | 10 - .../x/sys/unix/zsyscall_linux_arm64.go | 10 - .../x/sys/unix/zsyscall_linux_mips.go | 10 - .../x/sys/unix/zsyscall_linux_mips64.go | 10 - .../x/sys/unix/zsyscall_linux_mips64le.go | 10 - .../x/sys/unix/zsyscall_linux_mipsle.go | 10 - .../x/sys/unix/zsyscall_linux_ppc.go | 10 - .../x/sys/unix/zsyscall_linux_ppc64.go | 10 - .../x/sys/unix/zsyscall_linux_ppc64le.go | 10 - .../x/sys/unix/zsyscall_linux_riscv64.go | 10 - .../x/sys/unix/zsyscall_linux_s390x.go | 10 - .../x/sys/unix/zsyscall_linux_sparc64.go | 10 - .../x/sys/unix/zsyscall_netbsd_386.go | 20 +- .../x/sys/unix/zsyscall_netbsd_amd64.go | 20 +- .../x/sys/unix/zsyscall_netbsd_arm.go | 20 +- .../x/sys/unix/zsyscall_netbsd_arm64.go | 20 +- .../x/sys/unix/zsyscall_openbsd_386.go | 44 +- .../x/sys/unix/zsyscall_openbsd_386.s | 15 +- .../x/sys/unix/zsyscall_openbsd_amd64.go | 46 +- .../x/sys/unix/zsyscall_openbsd_amd64.s | 15 +- .../x/sys/unix/zsyscall_openbsd_arm.go | 44 +- .../x/sys/unix/zsyscall_openbsd_arm.s | 15 +- .../x/sys/unix/zsyscall_openbsd_arm64.go | 44 +- .../x/sys/unix/zsyscall_openbsd_arm64.s | 15 +- .../x/sys/unix/zsyscall_openbsd_mips64.go | 44 +- .../x/sys/unix/zsyscall_openbsd_mips64.s | 15 +- .../x/sys/unix/zsyscall_openbsd_ppc64.go | 44 +- .../x/sys/unix/zsyscall_openbsd_ppc64.s | 18 +- .../x/sys/unix/zsyscall_openbsd_riscv64.go | 44 +- .../x/sys/unix/zsyscall_openbsd_riscv64.s | 15 +- .../x/sys/unix/zsyscall_solaris_amd64.go | 26 +- .../x/sys/unix/zsyscall_zos_s390x.go | 12 +- .../x/sys/unix/ztypes_darwin_amd64.go | 11 + .../x/sys/unix/ztypes_darwin_arm64.go | 11 + .../x/sys/unix/ztypes_freebsd_386.go | 2 +- .../x/sys/unix/ztypes_freebsd_amd64.go | 2 +- .../x/sys/unix/ztypes_freebsd_arm.go | 2 +- .../x/sys/unix/ztypes_freebsd_arm64.go | 2 +- .../x/sys/unix/ztypes_freebsd_riscv64.go | 2 +- vendor/golang.org/x/sys/unix/ztypes_linux.go | 186 ++- .../golang.org/x/sys/unix/ztypes_linux_386.go | 2 +- .../x/sys/unix/ztypes_linux_amd64.go | 2 +- .../golang.org/x/sys/unix/ztypes_linux_arm.go | 2 +- .../x/sys/unix/ztypes_linux_arm64.go | 2 +- .../x/sys/unix/ztypes_linux_loong64.go | 2 +- .../x/sys/unix/ztypes_linux_mips.go | 2 +- .../x/sys/unix/ztypes_linux_mips64.go | 2 +- .../x/sys/unix/ztypes_linux_mips64le.go | 2 +- .../x/sys/unix/ztypes_linux_mipsle.go | 2 +- .../golang.org/x/sys/unix/ztypes_linux_ppc.go | 2 +- .../x/sys/unix/ztypes_linux_ppc64.go | 2 +- .../x/sys/unix/ztypes_linux_ppc64le.go | 2 +- .../x/sys/unix/ztypes_linux_riscv64.go | 2 +- .../x/sys/unix/ztypes_linux_s390x.go | 2 +- .../x/sys/unix/ztypes_linux_sparc64.go | 2 +- .../golang.org/x/sys/windows/env_windows.go | 6 +- .../golang.org/x/sys/windows/exec_windows.go | 7 +- vendor/golang.org/x/sys/windows/service.go | 7 + .../x/sys/windows/syscall_windows.go | 19 +- .../golang.org/x/sys/windows/types_windows.go | 95 +- .../x/sys/windows/zsyscall_windows.go | 44 +- .../x/text/encoding/internal/internal.go | 2 +- .../x/text/unicode/norm/forminfo.go | 2 +- vendor/modules.txt | 19 +- 229 files changed, 6370 insertions(+), 1683 deletions(-) create mode 100644 vendor/github.com/bits-and-blooms/bitset/.gitignore create mode 100644 vendor/github.com/bits-and-blooms/bitset/.travis.yml create mode 100644 vendor/github.com/bits-and-blooms/bitset/LICENSE create mode 100644 vendor/github.com/bits-and-blooms/bitset/README.md create mode 100644 vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml create mode 100644 vendor/github.com/bits-and-blooms/bitset/bitset.go create mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt.go create mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_19.go create mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go create mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s create mode 100644 vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go create mode 100644 vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go create mode 100644 vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv.go create mode 100644 vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go create mode 100644 vendor/golang.org/x/sys/unix/ioctl_signed.go rename vendor/golang.org/x/sys/unix/{ioctl.go => ioctl_unsigned.go} (76%) diff --git a/go.mod b/go.mod index ba48b6c36..101e59528 100644 --- a/go.mod +++ b/go.mod @@ -31,17 +31,18 @@ require ( github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.3.2 - github.com/stretchr/testify v1.8.0 - golang.org/x/crypto v0.1.0 + github.com/stretchr/testify v1.8.2 + golang.org/x/crypto v0.10.0 gopkg.in/ldap.v2 v2.5.1 ) require ( github.com/VividCortex/gohistogram v1.0.0 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/bits-and-blooms/bitset v1.7.0 // indirect github.com/cespare/xxhash/v2 v2.1.1 // indirect github.com/consensys/bavard v0.1.13 // indirect - github.com/consensys/gnark-crypto v0.9.1 // indirect + github.com/consensys/gnark-crypto v0.12.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.4.9 // indirect github.com/go-logfmt/logfmt v0.5.0 // indirect @@ -61,10 +62,11 @@ require ( github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.26.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect + github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/spf13/afero v1.1.2 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/spf13/jwalterweatherman v1.0.0 // indirect - github.com/stretchr/objx v0.4.0 // indirect + github.com/stretchr/objx v0.5.0 // indirect github.com/sykesm/zap-logfmt v0.0.4 // indirect github.com/weppos/publicsuffix-go v0.5.0 // indirect github.com/zmap/zcrypto v0.0.0-20190729165852-9051775e6a2e // indirect @@ -72,9 +74,9 @@ require ( go.uber.org/atomic v1.6.0 // indirect go.uber.org/multierr v1.5.0 // indirect go.uber.org/zap v1.16.0 // indirect - golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.5.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect google.golang.org/grpc v1.31.0 // indirect google.golang.org/protobuf v1.28.1 // indirect diff --git a/go.sum b/go.sum index 6bc525df1..9efced6dc 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 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/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo= +github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -37,8 +39,8 @@ github.com/cloudflare/redoctober v0.0.0-20171127175943-746a508df14c/go.mod h1:6S github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 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.9.1 h1:mru55qKdWl3E035hAoh1jj9d7hVnYY5pfb6tmovSmII= -github.com/consensys/gnark-crypto v0.9.1/go.mod h1:a2DQL4+5ywF6safEeZFEPGRiiGbjzGFRUN2sg06VuU4= +github.com/consensys/gnark-crypto v0.12.0 h1:1OnSpOykNkUIBIBJKdhwy2p0JlW5o+Az02ICzZmvvdg= +github.com/consensys/gnark-crypto v0.12.0/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -139,8 +141,8 @@ github.com/kisom/goutils v1.1.0/go.mod h1:+UBTfd78habUYWFbNWTJNG+jNG/i/lGURakr4A github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -217,6 +219,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +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.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -238,14 +242,16 @@ github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/sykesm/zap-logfmt v0.0.4 h1:U2WzRvmIWG1wDLCFY3sz8UeEmsdHQjHFNlIdmroVFaI= github.com/sykesm/zap-logfmt v0.0.4/go.mod h1:AuBd9xQjAe3URrWT1BBDk2v2onAZHkZkWRMiYZXiZWA= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -279,8 +285,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -288,7 +294,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -302,8 +308,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -332,13 +338,13 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -347,7 +353,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 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.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -374,8 +380,8 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzyc gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU= diff --git a/vendor/github.com/bits-and-blooms/bitset/.gitignore b/vendor/github.com/bits-and-blooms/bitset/.gitignore new file mode 100644 index 000000000..5c204d28b --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/.gitignore @@ -0,0 +1,26 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +target diff --git a/vendor/github.com/bits-and-blooms/bitset/.travis.yml b/vendor/github.com/bits-and-blooms/bitset/.travis.yml new file mode 100644 index 000000000..094aa5ce0 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/.travis.yml @@ -0,0 +1,37 @@ +language: go + +sudo: false + +branches: + except: + - release + +branches: + only: + - master + - travis + +go: + - "1.11.x" + - tip + +matrix: + allow_failures: + - go: tip + +before_install: + - if [ -n "$GH_USER" ]; then git config --global github.user ${GH_USER}; fi; + - if [ -n "$GH_TOKEN" ]; then git config --global github.token ${GH_TOKEN}; fi; + - go get github.com/mattn/goveralls + +before_script: + - make deps + +script: + - make qa + +after_failure: + - cat ./target/test/report.xml + +after_success: + - if [ "$TRAVIS_GO_VERSION" = "1.11.1" ]; then $HOME/gopath/bin/goveralls -covermode=count -coverprofile=target/report/coverage.out -service=travis-ci; fi; diff --git a/vendor/github.com/bits-and-blooms/bitset/LICENSE b/vendor/github.com/bits-and-blooms/bitset/LICENSE new file mode 100644 index 000000000..59cab8a93 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 Will Fitzgerald. 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/github.com/bits-and-blooms/bitset/README.md b/vendor/github.com/bits-and-blooms/bitset/README.md new file mode 100644 index 000000000..4b82fd178 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/README.md @@ -0,0 +1,137 @@ +# bitset + +*Go language library to map between non-negative integers and boolean values* + +[![Test](https://github.com/bits-and-blooms/bitset/workflows/Test/badge.svg)](https://github.com/willf/bitset/actions?query=workflow%3ATest) +[![Go Report Card](https://goreportcard.com/badge/github.com/willf/bitset)](https://goreportcard.com/report/github.com/willf/bitset) +[![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. +It should be more efficient than map[uint] bool. + +It provides methods for setting, clearing, flipping, and testing individual integers. + +But it also provides set intersection, union, difference, complement, and symmetric operations, as well as tests to check whether any, all, or no bits are set, and querying a bitset's current length and number of positive bits. + +BitSets are expanded to the size of the largest set bit; the memory allocation is approximately Max bits, where Max is the largest set bit. BitSets are never shrunk. On creation, a hint can be given for the number of bits that will be used. + +Many of the methods, including Set, Clear, and Flip, return a BitSet pointer, which allows for chaining. + +### Example use: + +```go +package main + +import ( + "fmt" + "math/rand" + + "github.com/bits-and-blooms/bitset" +) + +func main() { + fmt.Printf("Hello from BitSet!\n") + var b bitset.BitSet + // play some Go Fish + for i := 0; i < 100; i++ { + card1 := uint(rand.Intn(52)) + card2 := uint(rand.Intn(52)) + b.Set(card1) + if b.Test(card2) { + fmt.Println("Go Fish!") + } + b.Clear(card1) + } + + // Chaining + b.Set(10).Set(11) + + for i, e := b.NextSet(0); e; i, e = b.NextSet(i + 1) { + fmt.Println("The following bit is set:", i) + } + if b.Intersection(bitset.New(100).Set(10)).Count() == 1 { + fmt.Println("Intersection works.") + } else { + fmt.Println("Intersection doesn't work???") + } +} +``` + + +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. + +## 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). + +## 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 `uint64`). If so, the version will be bumped. + +## Installation + +```bash +go get github.com/bits-and-blooms/bitset +``` + +## Contributing + +If you wish to contribute to this project, please branch and issue a pull request against master ("[GitHub Flow](https://guides.github.com/introduction/flow/)") + +## Running all tests + +Before committing the code, please check if it passes tests, has adequate coverage, etc. +```bash +go test +go test -cover +``` diff --git a/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml b/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml new file mode 100644 index 000000000..f9b295918 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/azure-pipelines.yml @@ -0,0 +1,39 @@ +# Go +# Build your Go project. +# Add steps that test, save build artifacts, deploy, and more: +# https://docs.microsoft.com/azure/devops/pipelines/languages/go + +trigger: +- master + +pool: + vmImage: 'Ubuntu-16.04' + +variables: + GOBIN: '$(GOPATH)/bin' # Go binaries path + GOROOT: '/usr/local/go1.11' # Go installation path + GOPATH: '$(system.defaultWorkingDirectory)/gopath' # Go workspace path + modulePath: '$(GOPATH)/src/github.com/$(build.repository.name)' # Path to the module's code + +steps: +- script: | + mkdir -p '$(GOBIN)' + mkdir -p '$(GOPATH)/pkg' + mkdir -p '$(modulePath)' + shopt -s extglob + shopt -s dotglob + mv !(gopath) '$(modulePath)' + echo '##vso[task.prependpath]$(GOBIN)' + echo '##vso[task.prependpath]$(GOROOT)/bin' + displayName: 'Set up the Go workspace' + +- script: | + go version + go get -v -t -d ./... + if [ -f Gopkg.toml ]; then + curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh + dep ensure + fi + go build -v . + workingDirectory: '$(modulePath)' + displayName: 'Get dependencies, then build' diff --git a/vendor/github.com/bits-and-blooms/bitset/bitset.go b/vendor/github.com/bits-and-blooms/bitset/bitset.go new file mode 100644 index 000000000..237285b60 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/bitset.go @@ -0,0 +1,1036 @@ +/* +Package bitset implements bitsets, a mapping +between non-negative integers and boolean values. It should be more +efficient than map[uint] bool. + +It provides methods for setting, clearing, flipping, and testing +individual integers. + +But it also provides set intersection, union, difference, +complement, and symmetric operations, as well as tests to +check whether any, all, or no bits are set, and querying a +bitset's current length and number of positive bits. + +BitSets are expanded to the size of the largest set bit; the +memory allocation is approximately Max bits, where Max is +the largest set bit. BitSets are never shrunk. On creation, +a hint can be given for the number of bits that will be used. + +Many of the methods, including Set,Clear, and Flip, return +a BitSet pointer, which allows for chaining. + +Example use: + + import "bitset" + var b BitSet + b.Set(10).Set(11) + if b.Test(1000) { + b.Clear(1000) + } + if B.Intersection(bitset.New(100).Set(10)).Count() > 1 { + fmt.Println("Intersection works.") + } + +As an alternative to BitSets, one should check out the 'big' package, +which provides a (less set-theoretical) view of bitsets. +*/ +package bitset + +import ( + "bytes" + "encoding/base64" + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "io" + "strconv" +) + +// 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) + +// allBits has every bit set +const allBits uint64 = 0xffffffffffffffff + +// default binary BigEndian +var binaryOrder binary.ByteOrder = binary.BigEndian + +// default json encoding base64.URLEncoding +var base64Encoding = base64.URLEncoding + +// Base64StdEncoding Marshal/Unmarshal BitSet with base64.StdEncoding(Default: base64.URLEncoding) +func Base64StdEncoding() { base64Encoding = base64.StdEncoding } + +// LittleEndian Marshal/Unmarshal Binary as Little Endian(Default: binary.BigEndian) +func LittleEndian() { binaryOrder = binary.LittleEndian } + +// A BitSet is a set of bits. The zero value of a BitSet is an empty set of length 0. +type BitSet struct { + length uint + set []uint64 +} + +// Error is used to distinguish errors (panics) generated in this package. +type Error string + +// safeSet will fixup b.set to be non-nil and return the field value +func (b *BitSet) safeSet() []uint64 { + if b.set == nil { + b.set = make([]uint64, wordsNeeded(0)) + } + return b.set +} + +// 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 integers +func From(buf []uint64) *BitSet { + return FromWithLength(uint(len(buf))*64, buf) +} + +// FromWithLength constructs from an array of integers and length. +func FromWithLength(len uint, set []uint64) *BitSet { + return &BitSet{len, set} +} + +// Bytes returns the bitset as array of integers +func (b *BitSet) Bytes() []uint64 { + return b.set +} + +// wordsNeeded calculates the number of words needed for i bits +func wordsNeeded(i uint) int { + if i > (Cap() - wordSize + 1) { + return int(Cap() >> log2WordSize) + } + 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() { + if r := recover(); r != nil { + bset = &BitSet{ + 0, + make([]uint64, 0), + } + } + }() + + bset = &BitSet{ + length, + make([]uint64, wordsNeeded(length)), + } + + return bset +} + +// Cap returns the total possible capacity, or number of bits +func Cap() uint { + return ^uint(0) +} + +// Len returns the number of bits in the BitSet. +// Note the difference to method Count, see example. +func (b *BitSet) Len() uint { + return b.length +} + +// 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. +func (b *BitSet) Test(i uint) bool { + if i >= b.length { + return false + } + return b.set[i>>log2WordSize]&(1<= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) Set(i uint) *BitSet { + if i >= b.length { // if we need more bits, make 'em + b.extendSet(i) + } + b.set[i>>log2WordSize] |= 1 << wordsIndex(i) + return b +} + +// Clear bit i to 0 +func (b *BitSet) Clear(i uint) *BitSet { + if i >= b.length { + return b + } + b.set[i>>log2WordSize] &^= 1 << wordsIndex(i) + return b +} + +// SetTo sets bit i to value. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) SetTo(i uint, value bool) *BitSet { + if value { + return b.Set(i) + } + return b.Clear(i) +} + +// Flip bit at i. +// If i>= Cap(), this function will panic. +// Warning: using a very large value for 'i' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) Flip(i uint) *BitSet { + if i >= b.length { + return b.Set(i) + } + b.set[i>>log2WordSize] ^= 1 << wordsIndex(i) + return b +} + +// FlipRange bit in [start, end). +// If end>= Cap(), this function will panic. +// Warning: using a very large value for 'end' +// may lead to a memory shortage and a panic: the caller is responsible +// for providing sensible parameters in line with their memory capacity. +func (b *BitSet) FlipRange(start, end uint) *BitSet { + if start >= end { + return b + } + 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) << wordsIndex(start)) + for i := startWord; i < endWord; i++ { + b.set[i] = ^b.set[i] + } + if end&(wordSize-1) != 0 { + b.set[endWord] ^= ^uint64(0) >> wordsIndex(-end) + } + return b +} + +// Shrink shrinks BitSet so that the provided value is the last possible +// set value. It clears all bits > the provided index and reduces the size +// and length of the set. +// +// Note that the parameter value is not the new length in bits: it is the +// maximal value that can be stored in the bitset after the function call. +// The new length in bits is the parameter value + 1. Thus it is not possible +// to use this function to set the length to 0, the minimal value of the length +// after this function call is 1. +// +// A new slice is allocated to store the new bits, so you may see an increase in +// memory usage until the GC runs. Normally this should not be a problem, but if you +// have an extremely large BitSet its important to understand that the old BitSet will +// remain in memory until the GC frees it. +func (b *BitSet) Shrink(lastbitindex uint) *BitSet { + length := lastbitindex + 1 + idx := wordsNeeded(length) + if idx > len(b.set) { + return b + } + shrunk := make([]uint64, idx) + copy(shrunk, b.set[:idx]) + b.set = shrunk + b.length = length + lastWordUsedBits := length % 64 + if lastWordUsedBits != 0 { + b.set[idx-1] &= allBits >> uint64(64-wordsIndex(lastWordUsedBits)) + } + return b +} + +// Compact shrinks BitSet to so that we preserve all set bits, while minimizing +// memory usage. Compact calls Shrink. +func (b *BitSet) Compact() *BitSet { + idx := len(b.set) - 1 + for ; idx >= 0 && b.set[idx] == 0; idx-- { + } + newlength := uint((idx + 1) << log2WordSize) + if newlength >= b.length { + return b // nothing to do + } + if newlength > 0 { + return b.Shrink(newlength - 1) + } + // We preserve one word + return b.Shrink(63) +} + +// InsertAt takes an index which indicates where a bit should be +// inserted. Then it shifts all the bits in the set to the left by 1, starting +// from the given index position, and sets the index position to 0. +// +// Depending on the size of your BitSet, and where you are inserting the new entry, +// 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 + + // if length of set is a multiple of wordSize we need to allocate more space first + if b.isLenExactMultiple() { + b.set = append(b.set, uint64(0)) + } + + var i uint + for i = uint(len(b.set) - 1); i > insertAtElement; i-- { + // all elements above the position where we want to insert can simply by shifted + b.set[i] <<= 1 + + // we take the most significant bit of the previous element and set it as + // the least significant bit of the current element + b.set[i] |= (b.set[i-1] & 0x8000000000000000) >> 63 + } + + // generate a mask to extract the data that we need to shift left + // within the element where we insert a bit + dataMask := uint64(1)< 0x40000 { + buffer.WriteString("...") + break + } + buffer.WriteString(strconv.FormatInt(int64(i), 10)) + i, e = b.NextSet(i + 1) + if e { + buffer.WriteString(",") + } + } + buffer.WriteString("}") + return buffer.String() +} + +// DeleteAt deletes the bit at the given index position from +// within the bitset +// All the bits residing on the left of the deleted bit get +// shifted right by 1 +// The running time of this operation may potentially be +// relatively slow, O(length) +func (b *BitSet) DeleteAt(i uint) *BitSet { + // the index of the slice element where we'll delete a bit + deleteAtElement := i >> log2WordSize + + // generate a mask for the data that needs to be shifted right + // within that slice element that gets modified + dataMask := ^((uint64(1) << wordsIndex(i)) - 1) + + // extract the data that we'll shift right from the slice element + data := b.set[deleteAtElement] & dataMask + + // set the masked area to 0 while leaving the rest as it is + b.set[deleteAtElement] &= ^dataMask + + // shift the previously extracted data to the right and then + // set it in the previously masked area + b.set[deleteAtElement] |= (data >> 1) & dataMask + + // loop over all the consecutive slice elements to copy each + // lowest bit into the highest position of the previous element, + // then shift the entire content to the right by 1 + for i := int(deleteAtElement) + 1; i < len(b.set); i++ { + b.set[i-1] |= (b.set[i] & 1) << 63 + b.set[i] >>= 1 + } + + b.length = b.length - 1 + + return b +} + +// NextSet returns the next bit set from the specified index, +// including possibly the current index +// along with an error code (true = valid, false = no set bit found) +// for i,e := v.NextSet(0); e; i,e = v.NextSet(i + 1) {...} +// +// Users concerned with performance may want to use NextSetMany to +// retrieve several values at once. +func (b *BitSet) NextSet(i uint) (uint, bool) { + x := int(i >> log2WordSize) + if x >= len(b.set) { + return 0, false + } + w := b.set[x] + w = w >> wordsIndex(i) + if w != 0 { + return i + trailingZeroes64(w), true + } + x = x + 1 + for x < len(b.set) { + if b.set[x] != 0 { + return uint(x)*wordSize + trailingZeroes64(b.set[x]), true + } + x = x + 1 + + } + return 0, false +} + +// NextSetMany returns many next bit sets from the specified index, +// 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 +// } +// +// It is possible to retrieve all set bits as follow: +// +// 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. +func (b *BitSet) NextSetMany(i uint, buffer []uint) (uint, []uint) { + myanswer := buffer + capacity := cap(buffer) + x := int(i >> log2WordSize) + if x >= len(b.set) || capacity == 0 { + return 0, myanswer[:0] + } + skip := wordsIndex(i) + word := b.set[x] >> skip + myanswer = myanswer[:capacity] + size := int(0) + for word != 0 { + r := trailingZeroes64(word) + t := word & ((^word) + 1) + myanswer[size] = r + i + size++ + if size == capacity { + goto End + } + word = word ^ t + } + x++ + for idx, word := range b.set[x:] { + for word != 0 { + r := trailingZeroes64(word) + t := word & ((^word) + 1) + myanswer[size] = r + (uint(x+idx) << 6) + size++ + if size == capacity { + goto End + } + word = word ^ t + } + } +End: + if size > 0 { + return myanswer[size-1], myanswer[:size] + } + return 0, myanswer[:0] +} + +// NextClear returns the next clear bit from the specified index, +// including possibly the current index +// along with an error code (true = valid, false = no bit found i.e. all bits are set) +func (b *BitSet) NextClear(i uint) (uint, bool) { + x := int(i >> log2WordSize) + if x >= len(b.set) { + return 0, false + } + w := b.set[x] + w = w >> wordsIndex(i) + wA := allBits >> wordsIndex(i) + index := i + trailingZeroes64(^w) + if w != wA && index < b.length { + return index, true + } + x++ + for x < len(b.set) { + index = uint(x)*wordSize + trailingZeroes64(^b.set[x]) + if b.set[x] != allBits && index < b.length { + return index, true + } + x++ + } + return 0, false +} + +// ClearAll clears the entire BitSet +func (b *BitSet) ClearAll() *BitSet { + if b != nil && b.set != nil { + for i := range b.set { + b.set[i] = 0 + } + } + return b +} + +// wordCount returns the number of words used in a bit set +func (b *BitSet) wordCount() int { + return wordsNeededUnbound(b.length) +} + +// Clone this BitSet +func (b *BitSet) Clone() *BitSet { + c := New(b.length) + if b.set != nil { // Clone should not modify current object + copy(c.set, b.set) + } + return c +} + +// 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 + } + if b.set != nil { // Copy should not modify current object + copy(c.set, b.set) + } + count = c.length + 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 { + if b != nil && b.set != nil { + return uint(popcntSlice(b.set)) + } + return 0 +} + +// Equal tests the equivalence of two BitSets. +// False if they are of different sizes, otherwise true +// only if all the same bits are set +func (b *BitSet) Equal(c *BitSet) bool { + if c == nil || b == nil { + return c == b + } + if b.length != c.length { + return false + } + if b.length == 0 { // if they have both length == 0, then could have nil set + return true + } + wn := b.wordCount() + for p := 0; p < wn; p++ { + if c.set[p] != b.set[p] { + return false + } + } + return true +} + +func panicIfNull(b *BitSet) { + if b == nil { + panic(Error("BitSet must not be null")) + } +} + +// Difference of base set and other set +// This is the BitSet equivalent of &^ (and not) +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()) + } + for i := 0; i < l; i++ { + result.set[i] = b.set[i] &^ compare.set[i] + } + return +} + +// DifferenceCardinality computes the cardinality of the differnce +func (b *BitSet) DifferenceCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + cnt := uint64(0) + cnt += popcntMaskSlice(b.set[:l], compare.set[:l]) + cnt += popcntSlice(b.set[l:]) + return uint(cnt) +} + +// InPlaceDifference computes the difference of base set and other set +// This is the BitSet equivalent of &^ (and not) +func (b *BitSet) InPlaceDifference(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] + } +} + +// Convenience function: return two bitsets ordered by +// increasing length. Note: neither can be nil +func sortByLength(a *BitSet, b *BitSet) (ap *BitSet, bp *BitSet) { + if a.length <= b.length { + ap, bp = a, b + } else { + ap, bp = b, a + } + return +} + +// Intersection of base set and other set +// This is the BitSet equivalent of & (and) +func (b *BitSet) Intersection(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + result = New(b.length) + for i, word := range b.set { + result.set[i] = word & compare.set[i] + } + return +} + +// IntersectionCardinality computes the cardinality of the union +func (b *BitSet) IntersectionCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntAndSlice(b.set, compare.set) + return uint(cnt) +} + +// InPlaceIntersection destructively computes the intersection of +// base set and the compare set. +// This is the BitSet equivalent of & (and) +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] + } + for i := l; i < len(b.set); i++ { + b.set[i] = 0 + } + if compare.length > 0 { + if compare.length-1 >= b.length { + b.extendSet(compare.length - 1) + } + } +} + +// Union of base set and other set +// This is the BitSet equivalent of | (or) +func (b *BitSet) Union(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + result = compare.Clone() + for i, word := range b.set { + result.set[i] = word | compare.set[i] + } + return +} + +// UnionCardinality computes the cardinality of the uniton of the base set +// and the compare set. +func (b *BitSet) UnionCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntOrSlice(b.set, compare.set) + if len(compare.set) > len(b.set) { + cnt += popcntSlice(compare.set[len(b.set):]) + } + return uint(cnt) +} + +// InPlaceUnion creates the destructive union of base set and compare set. +// This is the BitSet equivalent of | (or). +func (b *BitSet) InPlaceUnion(compare *BitSet) { + panicIfNull(b) + panicIfNull(compare) + l := int(compare.wordCount()) + if l > int(b.wordCount()) { + l = int(b.wordCount()) + } + 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 len(compare.set) > l { + for i := l; i < len(compare.set); i++ { + b.set[i] = compare.set[i] + } + } +} + +// SymmetricDifference of base set and other set +// This is the BitSet equivalent of ^ (xor) +func (b *BitSet) SymmetricDifference(compare *BitSet) (result *BitSet) { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + // compare is bigger, so clone it + result = compare.Clone() + for i, word := range b.set { + result.set[i] = word ^ compare.set[i] + } + return +} + +// SymmetricDifferenceCardinality computes the cardinality of the symmetric difference +func (b *BitSet) SymmetricDifferenceCardinality(compare *BitSet) uint { + panicIfNull(b) + panicIfNull(compare) + b, compare = sortByLength(b, compare) + cnt := popcntXorSlice(b.set, compare.set) + if len(compare.set) > len(b.set) { + cnt += popcntSlice(compare.set[len(b.set):]) + } + return uint(cnt) +} + +// InPlaceSymmetricDifference creates the destructive SymmetricDifference of base set and other set +// This is the BitSet equivalent of ^ (xor) +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 && compare.length-1 >= b.length { + b.extendSet(compare.length - 1) + } + for i := 0; i < l; i++ { + b.set[i] ^= compare.set[i] + } + if len(compare.set) > l { + for i := l; i < len(compare.set); i++ { + b.set[i] = compare.set[i] + } + } +} + +// Is the length an exact multiple of word sizes? +func (b *BitSet) isLenExactMultiple() bool { + 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 - wordsIndex(b.length)) + } +} + +// Complement computes the (local) complement of a bitset (up to length bits) +func (b *BitSet) Complement() (result *BitSet) { + panicIfNull(b) + result = New(b.length) + for i, word := range b.set { + result.set[i] = ^word + } + result.cleanLastWord() + return +} + +// All returns true if all bits are set, false otherwise. Returns true for +// empty sets. +func (b *BitSet) All() bool { + panicIfNull(b) + return b.Count() == b.length +} + +// None returns true if no bit is set, false otherwise. Returns true for +// empty sets. +func (b *BitSet) None() bool { + panicIfNull(b) + if b != nil && b.set != nil { + for _, word := range b.set { + if word > 0 { + return false + } + } + } + return true +} + +// Any returns true if any bit is set, false otherwise +func (b *BitSet) Any() bool { + panicIfNull(b) + return !b.None() +} + +// 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) { + return false + } + } + return true +} + +// IsStrictSuperSet returns true if this is a strict superset of the other set +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 +func (b *BitSet) DumpAsBits() string { + if b.set == nil { + return "." + } + buffer := bytes.NewBufferString("") + i := len(b.set) - 1 + for ; i >= 0; i-- { + fmt.Fprintf(buffer, "%064b.", b.set[i]) + } + return buffer.String() +} + +// BinaryStorageSize returns the binary storage requirements (see WriteTo) in bytes. +func (b *BitSet) BinaryStorageSize() int { + return int(wordBytes + wordBytes*uint(b.wordCount())) +} + +// 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. +func (b *BitSet) WriteTo(stream io.Writer) (int64, error) { + buf := make([]byte, wordBytes) + length := uint64(b.length) + + // Write length + binaryOrder.PutUint64(buf, length) + n, err := stream.Write(buf) + if err != nil { + return int64(n), err + } + + nWords := b.wordCount() + for i := range b.set[:nWords] { + binaryOrder.PutUint64(buf, b.set[i]) + if nn, err := stream.Write(buf); err != nil { + return int64(i*int(wordBytes) + nn + n), 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. +func (b *BitSet) ReadFrom(stream io.Reader) (int64, error) { + buf := make([]byte, wordBytes) + + // Read length first + _, err := io.ReadFull(stream, buf[:]) + length := binaryOrder.Uint64(buf) + if err != nil { + if err == io.EOF { + err = io.ErrUnexpectedEOF + } + return 0, err + } + newlength := uint(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 + + for i := 0; i < nWords; i++ { + if _, err := io.ReadFull(stream, buf); 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.set[i] = binaryOrder.Uint64(buf) + } + + 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 + _, err := b.WriteTo(&buf) + if err != nil { + return []byte{}, err + } + + return buf.Bytes(), err +} + +// UnmarshalBinary decodes the binary form generated by MarshalBinary. +func (b *BitSet) UnmarshalBinary(data []byte) error { + buf := bytes.NewReader(data) + _, err := b.ReadFrom(buf) + return err +} + +// MarshalJSON marshals a BitSet as a JSON structure +func (b *BitSet) MarshalJSON() ([]byte, error) { + buffer := bytes.NewBuffer(make([]byte, 0, b.BinaryStorageSize())) + _, err := b.WriteTo(buffer) + if err != nil { + return nil, err + } + + // URLEncode all bytes + return json.Marshal(base64Encoding.EncodeToString(buffer.Bytes())) +} + +// UnmarshalJSON unmarshals a BitSet from JSON created using MarshalJSON +func (b *BitSet) UnmarshalJSON(data []byte) error { + // Unmarshal as string + var s string + err := json.Unmarshal(data, &s) + if err != nil { + return err + } + + // URLDecode string + buf, err := base64Encoding.DecodeString(s) + if err != nil { + return err + } + + _, err = b.ReadFrom(bytes.NewReader(buf)) + return err +} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt.go b/vendor/github.com/bits-and-blooms/bitset/popcnt.go new file mode 100644 index 000000000..76577a838 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt.go @@ -0,0 +1,53 @@ +package bitset + +// bit population count, take from +// https://code.google.com/p/go/issues/detail?id=4988#c11 +// credit: https://code.google.com/u/arnehormann/ +func popcount(x uint64) (n uint64) { + x -= (x >> 1) & 0x5555555555555555 + x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 + x += x >> 4 + x &= 0x0f0f0f0f0f0f0f0f + x *= 0x0101010101010101 + return x >> 56 +} + +func popcntSliceGo(s []uint64) uint64 { + cnt := uint64(0) + for _, x := range s { + cnt += popcount(x) + } + return cnt +} + +func popcntMaskSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] &^ m[i]) + } + return cnt +} + +func popcntAndSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] & m[i]) + } + return cnt +} + +func popcntOrSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] | m[i]) + } + return cnt +} + +func popcntXorSliceGo(s, m []uint64) uint64 { + cnt := uint64(0) + for i := range s { + cnt += popcount(s[i] ^ m[i]) + } + return cnt +} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go new file mode 100644 index 000000000..9a3766a01 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_19.go @@ -0,0 +1,46 @@ +//go:build go1.9 +// +build go1.9 + +package bitset + +import "math/bits" + +func popcntSlice(s []uint64) uint64 { + var cnt int + for _, x := range s { + cnt += bits.OnesCount64(x) + } + return uint64(cnt) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] &^ m[i]) + } + return uint64(cnt) +} + +func popcntAndSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] & m[i]) + } + return uint64(cnt) +} + +func popcntOrSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] | m[i]) + } + return uint64(cnt) +} + +func popcntXorSlice(s, m []uint64) uint64 { + var cnt int + for i := range s { + cnt += bits.OnesCount64(s[i] ^ m[i]) + } + return uint64(cnt) +} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go new file mode 100644 index 000000000..116e04440 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.go @@ -0,0 +1,68 @@ +//go:build !go1.9 && amd64 && !appengine +// +build !go1.9,amd64,!appengine + +package bitset + +// *** the following functions are defined in popcnt_amd64.s + +//go:noescape + +func hasAsm() bool + +// useAsm is a flag used to select the GO or ASM implementation of the popcnt function +var useAsm = hasAsm() + +//go:noescape + +func popcntSliceAsm(s []uint64) uint64 + +//go:noescape + +func popcntMaskSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntAndSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntOrSliceAsm(s, m []uint64) uint64 + +//go:noescape + +func popcntXorSliceAsm(s, m []uint64) uint64 + +func popcntSlice(s []uint64) uint64 { + if useAsm { + return popcntSliceAsm(s) + } + return popcntSliceGo(s) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + if useAsm { + return popcntMaskSliceAsm(s, m) + } + return popcntMaskSliceGo(s, m) +} + +func popcntAndSlice(s, m []uint64) uint64 { + if useAsm { + return popcntAndSliceAsm(s, m) + } + return popcntAndSliceGo(s, m) +} + +func popcntOrSlice(s, m []uint64) uint64 { + if useAsm { + return popcntOrSliceAsm(s, m) + } + return popcntOrSliceGo(s, m) +} + +func popcntXorSlice(s, m []uint64) uint64 { + if useAsm { + return popcntXorSliceAsm(s, m) + } + return popcntXorSliceGo(s, m) +} diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s new file mode 100644 index 000000000..666c0dcc1 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_amd64.s @@ -0,0 +1,104 @@ +// +build !go1.9 +// +build amd64,!appengine + +TEXT ·hasAsm(SB),4,$0-1 +MOVQ $1, AX +CPUID +SHRQ $23, CX +ANDQ $1, CX +MOVB CX, ret+0(FP) +RET + +#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2 + +TEXT ·popcntSliceAsm(SB),4,$0-32 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntSliceEnd +popcntSliceLoop: +BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX +ADDQ DX, AX +ADDQ $8, SI +LOOP popcntSliceLoop +popcntSliceEnd: +MOVQ AX, ret+24(FP) +RET + +TEXT ·popcntMaskSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntMaskSliceEnd +MOVQ m+24(FP), DI +popcntMaskSliceLoop: +MOVQ (DI), DX +NOTQ DX +ANDQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntMaskSliceLoop +popcntMaskSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntAndSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntAndSliceEnd +MOVQ m+24(FP), DI +popcntAndSliceLoop: +MOVQ (DI), DX +ANDQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntAndSliceLoop +popcntAndSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntOrSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntOrSliceEnd +MOVQ m+24(FP), DI +popcntOrSliceLoop: +MOVQ (DI), DX +ORQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntOrSliceLoop +popcntOrSliceEnd: +MOVQ AX, ret+48(FP) +RET + +TEXT ·popcntXorSliceAsm(SB),4,$0-56 +XORQ AX, AX +MOVQ s+0(FP), SI +MOVQ s_len+8(FP), CX +TESTQ CX, CX +JZ popcntXorSliceEnd +MOVQ m+24(FP), DI +popcntXorSliceLoop: +MOVQ (DI), DX +XORQ (SI), DX +POPCNTQ_DX_DX +ADDQ DX, AX +ADDQ $8, SI +ADDQ $8, DI +LOOP popcntXorSliceLoop +popcntXorSliceEnd: +MOVQ AX, ret+48(FP) +RET diff --git a/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go b/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go new file mode 100644 index 000000000..9e0ad464e --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/popcnt_generic.go @@ -0,0 +1,25 @@ +//go:build !go1.9 && (!amd64 || appengine) +// +build !go1.9 +// +build !amd64 appengine + +package bitset + +func popcntSlice(s []uint64) uint64 { + return popcntSliceGo(s) +} + +func popcntMaskSlice(s, m []uint64) uint64 { + return popcntMaskSliceGo(s, m) +} + +func popcntAndSlice(s, m []uint64) uint64 { + return popcntAndSliceGo(s, m) +} + +func popcntOrSlice(s, m []uint64) uint64 { + return popcntOrSliceGo(s, m) +} + +func popcntXorSlice(s, m []uint64) uint64 { + return popcntXorSliceGo(s, m) +} 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 new file mode 100644 index 000000000..12336e76a --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_18.go @@ -0,0 +1,15 @@ +//go:build !go1.9 +// +build !go1.9 + +package bitset + +var deBruijn = [...]byte{ + 0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4, + 62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5, + 63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11, + 54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6, +} + +func trailingZeroes64(v uint64) uint { + return uint(deBruijn[((v&-v)*0x03f79d71b4ca8b09)>>58]) +} 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 new file mode 100644 index 000000000..cfb0a8409 --- /dev/null +++ b/vendor/github.com/bits-and-blooms/bitset/trailing_zeros_19.go @@ -0,0 +1,10 @@ +//go:build go1.9 +// +build go1.9 + +package bitset + +import "math/bits" + +func trailingZeroes64(v uint64) uint { + return uint(bits.TrailingZeros64(v)) +} 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 index 8abee780d..43fbe1f6c 100644 --- 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 @@ -40,7 +40,8 @@ import ( // ID bls377 ID const ID = ecc.BLS12_377 -// bCurveCoeff b coeff of the curve Y²=X³+b +// aCurveCoeff is the a coefficients of the curve Y²=X³+ax+b +var aCurveCoeff fp.Element var bCurveCoeff fp.Element // twist @@ -97,7 +98,7 @@ type E6 = fptower.E6 type E12 = fptower.E12 func init() { - + aCurveCoeff.SetUint64(0) bCurveCoeff.SetUint64(1) // D-twist twist.A1.SetUint64(1) @@ -148,3 +149,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/bls12-377/fp/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fp/element.go index 3a3ccdd3f..81a730fbd 100644 --- 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 @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/bits-and-blooms/bitset" "github.com/consensys/gnark-crypto/field/hash" "github.com/consensys/gnark-crypto/field/pool" ) @@ -241,7 +242,7 @@ func (z *Element) IsZero() bool { // 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 + 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. @@ -355,7 +356,7 @@ func (z *Element) SetRandom() (*Element, error) { return nil, err } - // Clear unused bits in in the most signicant byte to increase probability + // Clear unused bits in in the most significant byte to increase probability // that the candidate is < q. bytes[k-1] &= uint8(int(1<= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -1063,6 +1064,11 @@ func (z *Element) Marshal() []byte { 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 { 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 index e75796169..3fe113710 100644 --- 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 @@ -19,8 +19,13 @@ package fp import ( "bytes" "encoding/binary" + "fmt" "io" + "runtime" "strings" + "sync" + "sync/atomic" + "unsafe" ) // Vector represents a slice of Element. @@ -73,6 +78,71 @@ func (vector *Vector) WriteTo(w io.Writer) (int64, error) { 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) { @@ -130,3 +200,56 @@ func (vector Vector) Less(i, j int) bool { 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/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/fr/element.go index b95577df3..07be74489 100644 --- 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 @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/bits-and-blooms/bitset" "github.com/consensys/gnark-crypto/field/hash" "github.com/consensys/gnark-crypto/field/pool" ) @@ -231,7 +232,7 @@ func (z *Element) IsZero() bool { // IsOne returns z == 1 func (z *Element) IsOne() bool { - return (z[3] ^ 958099254763297437 | z[2] ^ 1646089257421115374 | z[1] ^ 8239323489949974514 | z[0] ^ 9015221291577245683) == 0 + return ((z[3] ^ 958099254763297437) | (z[2] ^ 1646089257421115374) | (z[1] ^ 8239323489949974514) | (z[0] ^ 9015221291577245683)) == 0 } // IsUint64 reports whether z can be represented as an uint64. @@ -333,7 +334,7 @@ func (z *Element) SetRandom() (*Element, error) { return nil, err } - // Clear unused bits in in the most signicant byte to increase probability + // Clear unused bits in in the most significant byte to increase probability // that the candidate is < q. bytes[k-1] &= uint8(int(1<= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -901,6 +902,11 @@ func (z *Element) Marshal() []byte { 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 { 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 index c85a3c134..00ad8a898 100644 --- 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 @@ -19,8 +19,13 @@ package fr import ( "bytes" "encoding/binary" + "fmt" "io" + "runtime" "strings" + "sync" + "sync/atomic" + "unsafe" ) // Vector represents a slice of Element. @@ -73,6 +78,69 @@ func (vector *Vector) WriteTo(w io.Writer) (int64, error) { 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) { @@ -130,3 +198,56 @@ func (vector Vector) Less(i, j int) bool { 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 index b5b6f65e6..17ea4160f 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g1.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/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. @@ -92,6 +92,16 @@ 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 inefficient compared to Jacobian func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { @@ -624,6 +634,10 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { 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() { @@ -1017,7 +1031,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add p.AddMixed(&baseTableAff[(digit>>1)-1]) 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 index c2155c8dc..0f06e46fa 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/g2.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/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. @@ -81,6 +81,16 @@ 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 inefficient compared to Jacobian func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { @@ -562,6 +572,10 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { 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() { @@ -934,7 +948,7 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add p.AddAssign(&baseTable[(digit>>1)-1]) 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 index 6d5762e3a..20306ba87 100644 --- 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 @@ -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. @@ -166,9 +166,9 @@ func g1MulByZ(z *fp.Element, x *fp.Element) { } // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method -// mapToCurve1 implements the SSWU map +// MapToCurve1 implements the SSWU map // No cofactor clearing or isogeny -func mapToCurve1(u *fp.Element) G1Affine { +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} @@ -268,7 +268,7 @@ func g1Sgn0(z *fp.Element) uint64 { // MapToG1 invokes the SSWU map, and guarantees that the result is in g1 func MapToG1(u fp.Element) G1Affine { - res := mapToCurve1(&u) + res := MapToCurve1(&u) //this is in an isogenous curve g1Isogeny(&res) res.ClearCofactor(&res) @@ -287,7 +287,7 @@ func EncodeToG1(msg, dst []byte) (G1Affine, error) { return res, err } - res = mapToCurve1(&u[0]) + res = MapToCurve1(&u[0]) //this is in an isogenous curve g1Isogeny(&res) @@ -305,8 +305,8 @@ func HashToG1(msg, dst []byte) (G1Affine, error) { return G1Affine{}, err } - Q0 := mapToCurve1(&u[0]) - Q1 := mapToCurve1(&u[1]) + Q0 := MapToCurve1(&u[0]) + Q1 := MapToCurve1(&u[1]) //TODO (perf): Add in E' first, then apply isogeny g1Isogeny(&Q0) 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 index 03f649caa..66aae9fcc 100644 --- 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 @@ -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. @@ -613,9 +613,9 @@ func g2MulByZ(z *fptower.E2, x *fptower.E2) { } // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method -// mapToCurve2 implements the SSWU map +// MapToCurve2 implements the SSWU map // No cofactor clearing or isogeny -func mapToCurve2(u *fptower.E2) G2Affine { +func MapToCurve2(u *fptower.E2) G2Affine { var sswuIsoCurveCoeffA = fptower.E2{ A0: fp.Element{4274545572028848265, 14157081418478689358, 13123833976752631407, 4466041663276938746, 9062541850312583986, 90030181981586611}, @@ -739,7 +739,7 @@ func g2Sgn0(z *fptower.E2) uint64 { // MapToG2 invokes the SSWU map, and guarantees that the result is in g2 func MapToG2(u fptower.E2) G2Affine { - res := mapToCurve2(&u) + res := MapToCurve2(&u) //this is in an isogenous curve g2Isogeny(&res) res.ClearCofactor(&res) @@ -758,7 +758,7 @@ func EncodeToG2(msg, dst []byte) (G2Affine, error) { return res, err } - res = mapToCurve2(&fptower.E2{ + res = MapToCurve2(&fptower.E2{ A0: u[0], A1: u[1], }) @@ -779,11 +779,11 @@ func HashToG2(msg, dst []byte) (G2Affine, error) { return G2Affine{}, err } - Q0 := mapToCurve2(&fptower.E2{ + Q0 := MapToCurve2(&fptower.E2{ A0: u[0], A1: u[1], }) - Q1 := mapToCurve2(&fptower.E2{ + Q1 := MapToCurve2(&fptower.E2{ A0: u[2+0], A1: u[2+1], }) 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 index 0ec192019..49751a939 100644 --- 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 @@ -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/bls12-377/internal/fptower/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/asm_noadx.go index 6a09c11c4..c6a97081f 100644 --- 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 @@ -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/bls12-377/internal/fptower/e12.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e12.go index de9c52aa9..d2de48d6b 100644 --- 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 @@ -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. @@ -36,7 +36,7 @@ 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) } @@ -99,7 +99,7 @@ func (z *E12) SetRandom() (*E12, 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 *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } @@ -230,15 +230,17 @@ func (z *E12) DecompressKarabina(x *E12) *E12 { var one E2 one.SetOne() - // g3 == 0 - if x.C1.B2.IsZero() { + 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) - // g3 != 0 - } else { + 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 @@ -302,20 +304,24 @@ func BatchDecompressKarabina(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++ { - // g3 == 0 - if x[i].C1.B2.IsZero() { + 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) - // g3 != 0 - } else { + 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 @@ -335,6 +341,10 @@ func BatchDecompressKarabina(x []E12) []E12 { 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]) @@ -640,7 +650,7 @@ 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) } @@ -713,11 +723,11 @@ func (z *E12) SetBytes(e []byte) error { return nil } -// IsInSubGroup ensures GT/E12 is in correct sugroup +// IsInSubGroup ensures GT/E12 is in correct subgroup func (z *E12) IsInSubGroup() bool { var a, b E12 - // check z^(Phi_k(p)) == 1 + // check z^(phi_k(p)) == 1 a.FrobeniusSquare(z) b.FrobeniusSquare(&a).Mul(&b, z) 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 index 86a918d84..6888dfc4f 100644 --- 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 @@ -61,3 +61,53 @@ func (z *E12) MulBy034(c0, c3, c4 *E2) *E12 { 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 index 640fd5209..874802d74 100644 --- 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 @@ -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. @@ -203,7 +203,7 @@ func (z *E2) Exp(x E2, k *big.Int) *E2 { } // 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 10) 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 index 7145007fa..ac68ffa57 100644 --- 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 @@ -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. 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 index 0ce4d8333..6fe47c411 100644 --- 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 @@ -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/bls12-377/internal/fptower/e6.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower/e6.go index 8ae7216ec..128007df2 100644 --- 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 @@ -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) } @@ -126,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 { 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 index b71e1c2dc..317f7c535 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/marshal.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/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. @@ -32,24 +32,28 @@ import ( // 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 -// -// 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. +// 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 @@ -99,8 +103,38 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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) @@ -125,6 +159,18 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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]) @@ -133,6 +179,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -153,6 +206,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -166,12 +226,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) @@ -184,6 +243,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -199,7 +265,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { } } else { var r bool - if r, err = ((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])); err != nil { + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { return } compressed[i] = !r @@ -225,7 +291,6 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return nil case *[]G2Affine: - var sliceLen uint32 sliceLen, err = dec.readUint32() if err != nil { return @@ -243,6 +308,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -258,7 +330,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { } } else { var r bool - if r, err = ((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])); err != nil { + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { return } compressed[i] = !r @@ -313,6 +385,24 @@ 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 +} + +// 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)) @@ -365,6 +455,19 @@ 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()) { @@ -383,6 +486,10 @@ func (enc *Encoder) encode(v interface{}) (err error) { 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[:]) @@ -419,6 +526,17 @@ func (enc *Encoder) encode(v interface{}) (err error) { 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))) @@ -486,6 +604,10 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { 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[:]) @@ -522,6 +644,17 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { 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))) @@ -571,6 +704,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 = 48 @@ -583,7 +761,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 @@ -667,6 +845,11 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { // 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 { @@ -674,13 +857,19 @@ 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 } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +985,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er 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 isInfinity, nil } @@ -830,7 +1022,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 @@ -861,7 +1053,7 @@ 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 + // 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) @@ -920,6 +1112,11 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { // 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 { @@ -927,13 +1124,19 @@ 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 } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1063,9 +1266,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er 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 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 index f75f78aa0..8ae82e0a3 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/multiexp.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/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. @@ -41,11 +41,12 @@ func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc. // // 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 @@ -55,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) @@ -65,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) @@ -75,7 +76,7 @@ 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") } @@ -105,29 +106,51 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.Mul C := bestC(nbPoints) nbChunks := int(computeNbChunks(C)) - // if we don't utilise all the tasks (CPU in the default case) that we could, let's see if it's worth it to split - if config.NbTasks > 1 && nbChunks < config.NbTasks { - // before spliting, let's see if we endup with more tasks than thread; - cSplit := bestC(nbPoints / 2) - nbChunksPostSplit := int(computeNbChunks(cSplit)) - nbTasksPostSplit := nbChunksPostSplit * 2 - if (nbTasksPostSplit <= config.NbTasks/2) || (nbTasksPostSplit-config.NbTasks/2) <= (config.NbTasks-nbChunks) { - // if postSplit we still have less tasks than available CPU - // or if we have more tasks BUT the difference of CPU usage is in our favor, we split. - config.NbTasks /= 2 - 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 + // 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 @@ -149,6 +172,20 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co 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-- { @@ -161,8 +198,12 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co // else what would happen is this go routine would finish much later than the others. chSplit := make(chan g1JacExtended, 2) split := n / 2 - go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split]) - go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n]) + + 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 @@ -172,7 +213,7 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co }(j) continue } - go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n]) + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) } return msmReduceChunkG1Affine(p, int(c), chChunks[:]) @@ -180,7 +221,7 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co // 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) { +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: @@ -298,11 +339,12 @@ func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc. // // 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 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 @@ -312,7 +354,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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) @@ -322,7 +364,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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) @@ -332,7 +374,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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") } @@ -362,29 +404,51 @@ func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.Mul C := bestC(nbPoints) nbChunks := int(computeNbChunks(C)) - // if we don't utilise all the tasks (CPU in the default case) that we could, let's see if it's worth it to split - if config.NbTasks > 1 && nbChunks < config.NbTasks { - // before spliting, let's see if we endup with more tasks than thread; - cSplit := bestC(nbPoints / 2) - nbChunksPostSplit := int(computeNbChunks(cSplit)) - nbTasksPostSplit := nbChunksPostSplit * 2 - if (nbTasksPostSplit <= config.NbTasks/2) || (nbTasksPostSplit-config.NbTasks/2) <= (config.NbTasks-nbChunks) { - // if postSplit we still have less tasks than available CPU - // or if we have more tasks BUT the difference of CPU usage is in our favor, we split. - config.NbTasks /= 2 - 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 + // 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 @@ -406,6 +470,20 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co 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-- { @@ -418,8 +496,12 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co // else what would happen is this go routine would finish much later than the others. chSplit := make(chan g2JacExtended, 2) split := n / 2 - go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split]) - go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n]) + + 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 @@ -429,7 +511,7 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co }(j) continue } - go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n]) + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) } return msmReduceChunkG2Affine(p, int(c), chChunks[:]) @@ -437,7 +519,7 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co // 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) { +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: @@ -552,13 +634,13 @@ type selector struct { } // return number of chunks for a given window size c -// the last chunk may be bigger to accomodate a potential carry from the NAF decomposition +// 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 accomodate a carry (from the NAF decomposition) +// 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 @@ -577,11 +659,16 @@ type chunkStat struct { } // 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 +// 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) @@ -634,7 +721,7 @@ func partitionScalars(scalars []fr.Element, c uint64, nbTasks int) ([]uint16, [] 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 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. if digit > max { digit -= (1 << c) 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 index 5aa3546b5..422862c77 100644 --- 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 @@ -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. @@ -37,7 +37,13 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP chRes chan<- g1JacExtended, c uint64, points []G1Affine, - digits []uint16) { + 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 @@ -47,7 +53,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP // 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 immediatly + // 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. @@ -220,12 +226,18 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].ZZ.IsZero() { + 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 } @@ -353,7 +365,13 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP chRes chan<- g2JacExtended, c uint64, points []G2Affine, - digits []uint16) { + 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 @@ -363,7 +381,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP // 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 immediatly + // 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. @@ -536,12 +554,18 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].ZZ.IsZero() { + 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 } 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 index e01f5567f..0df516f5b 100644 --- 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 @@ -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. @@ -20,7 +20,13 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, chRes chan<- g1JacExtended, c uint64, points []G1Affine, - digits []uint16) { + 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++ { @@ -33,7 +39,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add buckets[(digit>>1)-1].addMixed(&points[i]) @@ -50,12 +56,18 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { + 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 } @@ -97,7 +109,13 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, chRes chan<- g2JacExtended, c uint64, points []G2Affine, - digits []uint16) { + 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++ { @@ -110,7 +128,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add buckets[(digit>>1)-1].addMixed(&points[i]) @@ -127,12 +145,18 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { + 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 } 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 index b1ed68e1a..f670902e4 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-377/pairing.go @@ -78,6 +78,12 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { 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 @@ -104,7 +110,7 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { } // MillerLoop computes the multi-Miller loop -// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = ∏ᵢ { fᵢ_{x,Qᵢ}(Pᵢ) } func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // check input size match n := len(P) @@ -134,49 +140,113 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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) + } - 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] + } - // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l) - // line eval - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) + // 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) } - for i := len(loopCounter) - 3; i >= 0; i-- { + // 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].DoubleStep(&l) - // line eval - 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] == 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) + } } - if loopCounter[i] == 0 { - continue - } + } - for k := 0; k < n; k++ { - qProj[k].AddMixedStep(&l, &q[k]) - // line eval - l.r0.MulByElement(&l.r0, &p[k].Y) - l.r1.MulByElement(&l.r1, &p[k].X) - result.MulBy034(&l.r0, &l.r1, &l.r2) - } + // 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 +// 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 @@ -215,9 +285,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 @@ -251,3 +321,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/bls12-381/bls12-381.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/bls12-381.go index 796369ed6..86ab933a1 100644 --- 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 @@ -40,7 +40,8 @@ import ( // ID bls381 ID const ID = ecc.BLS12_381 -// bCurveCoeff b coeff of the curve Y²=X³+b +// aCurveCoeff is the a coefficients of the curve Y²=X³+ax+b +var aCurveCoeff fp.Element var bCurveCoeff fp.Element // twist @@ -85,8 +86,17 @@ var endo struct { // seed x₀ of the curve var xGen big.Int -func init() { +// 𝔽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) @@ -140,3 +150,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/bls12-381/fp/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fp/element.go index 198dc73c0..f5c2df0c2 100644 --- 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 @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/bits-and-blooms/bitset" "github.com/consensys/gnark-crypto/field/hash" "github.com/consensys/gnark-crypto/field/pool" ) @@ -241,7 +242,7 @@ func (z *Element) IsZero() bool { // 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 + 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. @@ -355,7 +356,7 @@ func (z *Element) SetRandom() (*Element, error) { return nil, err } - // Clear unused bits in in the most signicant byte to increase probability + // Clear unused bits in in the most significant byte to increase probability // that the candidate is < q. bytes[k-1] &= uint8(int(1<= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -1063,6 +1064,11 @@ func (z *Element) Marshal() []byte { 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 { 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 index e75796169..3fe113710 100644 --- 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 @@ -19,8 +19,13 @@ package fp import ( "bytes" "encoding/binary" + "fmt" "io" + "runtime" "strings" + "sync" + "sync/atomic" + "unsafe" ) // Vector represents a slice of Element. @@ -73,6 +78,71 @@ func (vector *Vector) WriteTo(w io.Writer) (int64, error) { 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) { @@ -130,3 +200,56 @@ func (vector Vector) Less(i, j int) bool { 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/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/fr/element.go index 4a8842090..aa6c47cdd 100644 --- 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 @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/bits-and-blooms/bitset" "github.com/consensys/gnark-crypto/field/hash" "github.com/consensys/gnark-crypto/field/pool" ) @@ -231,7 +232,7 @@ func (z *Element) IsZero() bool { // IsOne returns z == 1 func (z *Element) IsOne() bool { - return (z[3] ^ 1739710354780652911 | z[2] ^ 11064306276430008309 | z[1] ^ 6378425256633387010 | z[0] ^ 8589934590) == 0 + return ((z[3] ^ 1739710354780652911) | (z[2] ^ 11064306276430008309) | (z[1] ^ 6378425256633387010) | (z[0] ^ 8589934590)) == 0 } // IsUint64 reports whether z can be represented as an uint64. @@ -333,7 +334,7 @@ func (z *Element) SetRandom() (*Element, error) { return nil, err } - // Clear unused bits in in the most signicant byte to increase probability + // Clear unused bits in in the most significant byte to increase probability // that the candidate is < q. bytes[k-1] &= uint8(int(1<= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -901,6 +902,11 @@ func (z *Element) Marshal() []byte { 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 { 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 index c85a3c134..00ad8a898 100644 --- 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 @@ -19,8 +19,13 @@ package fr import ( "bytes" "encoding/binary" + "fmt" "io" + "runtime" "strings" + "sync" + "sync/atomic" + "unsafe" ) // Vector represents a slice of Element. @@ -73,6 +78,69 @@ func (vector *Vector) WriteTo(w io.Writer) (int64, error) { 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) { @@ -130,3 +198,56 @@ func (vector Vector) Less(i, j int) bool { 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 index 6f93fe409..8eb803c3b 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g1.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/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. @@ -92,6 +92,16 @@ 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 inefficient compared to Jacobian func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { @@ -624,6 +634,10 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { 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() { @@ -1017,7 +1031,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add p.AddMixed(&baseTableAff[(digit>>1)-1]) 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 index d30c7b34b..798337382 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/g2.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/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. @@ -81,6 +81,16 @@ 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 inefficient compared to Jacobian func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { @@ -563,6 +573,10 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { 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() { @@ -935,7 +949,7 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add p.AddAssign(&baseTable[(digit>>1)-1]) 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 index 3f57d725a..715278283 100644 --- 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 @@ -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. @@ -177,9 +177,9 @@ func g1MulByZ(z *fp.Element, x *fp.Element) { } // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method -// mapToCurve1 implements the SSWU map +// MapToCurve1 implements the SSWU map // No cofactor clearing or isogeny -func mapToCurve1(u *fp.Element) G1Affine { +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} @@ -279,7 +279,7 @@ func g1Sgn0(z *fp.Element) uint64 { // MapToG1 invokes the SSWU map, and guarantees that the result is in g1 func MapToG1(u fp.Element) G1Affine { - res := mapToCurve1(&u) + res := MapToCurve1(&u) //this is in an isogenous curve g1Isogeny(&res) res.ClearCofactor(&res) @@ -298,7 +298,7 @@ func EncodeToG1(msg, dst []byte) (G1Affine, error) { return res, err } - res = mapToCurve1(&u[0]) + res = MapToCurve1(&u[0]) //this is in an isogenous curve g1Isogeny(&res) @@ -316,8 +316,8 @@ func HashToG1(msg, dst []byte) (G1Affine, error) { return G1Affine{}, err } - Q0 := mapToCurve1(&u[0]) - Q1 := mapToCurve1(&u[1]) + Q0 := MapToCurve1(&u[0]) + Q1 := MapToCurve1(&u[1]) //TODO (perf): Add in E' first, then apply isogeny g1Isogeny(&Q0) 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 index ace9c207a..4feafbfb1 100644 --- 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 @@ -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. @@ -213,9 +213,9 @@ func g2MulByZ(z *fptower.E2, x *fptower.E2) { } // https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-simplified-swu-method -// mapToCurve2 implements the SSWU map +// MapToCurve2 implements the SSWU map // No cofactor clearing or isogeny -func mapToCurve2(u *fptower.E2) G2Affine { +func MapToCurve2(u *fptower.E2) G2Affine { var sswuIsoCurveCoeffA = fptower.E2{ A0: fp.Element{0}, @@ -339,7 +339,7 @@ func g2Sgn0(z *fptower.E2) uint64 { // MapToG2 invokes the SSWU map, and guarantees that the result is in g2 func MapToG2(u fptower.E2) G2Affine { - res := mapToCurve2(&u) + res := MapToCurve2(&u) //this is in an isogenous curve g2Isogeny(&res) res.ClearCofactor(&res) @@ -358,7 +358,7 @@ func EncodeToG2(msg, dst []byte) (G2Affine, error) { return res, err } - res = mapToCurve2(&fptower.E2{ + res = MapToCurve2(&fptower.E2{ A0: u[0], A1: u[1], }) @@ -379,11 +379,11 @@ func HashToG2(msg, dst []byte) (G2Affine, error) { return G2Affine{}, err } - Q0 := mapToCurve2(&fptower.E2{ + Q0 := MapToCurve2(&fptower.E2{ A0: u[0], A1: u[1], }) - Q1 := mapToCurve2(&fptower.E2{ + Q1 := MapToCurve2(&fptower.E2{ A0: u[2+0], A1: u[2+1], }) 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 index 0ec192019..49751a939 100644 --- 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 @@ -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/bls12-381/internal/fptower/asm_noadx.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/asm_noadx.go index 6a09c11c4..c6a97081f 100644 --- 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 @@ -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/bls12-381/internal/fptower/e12.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e12.go index 35a43eb6d..1ccfa6c70 100644 --- 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 @@ -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. @@ -36,7 +36,7 @@ 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) } @@ -99,7 +99,7 @@ func (z *E12) SetRandom() (*E12, 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 *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } @@ -230,15 +230,17 @@ func (z *E12) DecompressKarabina(x *E12) *E12 { var one E2 one.SetOne() - // g3 == 0 - if x.C1.B2.IsZero() { + 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) - // g3 != 0 - } else { + 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 @@ -302,20 +304,24 @@ func BatchDecompressKarabina(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++ { - // g3 == 0 - if x[i].C1.B2.IsZero() { + 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) - // g3 != 0 - } else { + 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 @@ -335,6 +341,10 @@ func BatchDecompressKarabina(x []E12) []E12 { 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]) @@ -640,7 +650,7 @@ 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) } @@ -713,11 +723,11 @@ func (z *E12) SetBytes(e []byte) error { return nil } -// IsInSubGroup ensures GT/E12 is in correct sugroup +// IsInSubGroup ensures GT/E12 is in correct subgroup func (z *E12) IsInSubGroup() bool { var a, b E12 - // check z^(Phi_k(p)) == 1 + // check z^(phi_k(p)) == 1 a.FrobeniusSquare(z) b.FrobeniusSquare(&a).Mul(&b, z) 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 index 4aaf83074..880520f81 100644 --- 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 @@ -67,8 +67,8 @@ func (z *E12) MulBy014(c0, c1, c4 *E2) *E12 { } // Mul014By014 multiplication of sparse element (c0,c1,0,0,c4,0) by sparse element (d0,d1,0,0,d4,0) -func (z *E12) Mul014By014(d0, d1, d4, c0, c1, c4 *E2) *E12 { - var tmp, x0, x1, x4, x04, x01, x14 E2 +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) @@ -88,13 +88,30 @@ func (z *E12) Mul014By014(d0, d1, d4, c0, c1, c4 *E2) *E12 { Sub(&x14, &x1). Sub(&x14, &x4) - z.C0.B0.MulByNonResidue(&x4). - Add(&z.C0.B0, &x0) - z.C0.B1.Set(&x01) - z.C0.B2.Set(&x1) - z.C1.B0.SetZero() - z.C1.B1.Set(&x04) - z.C1.B2.Set(&x14) + 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 index 45338f189..0390e7e4b 100644 --- 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 @@ -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. @@ -214,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) 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 index 471a47bd6..5121f7cca 100644 --- 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 @@ -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. 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 index 0ce4d8333..6fe47c411 100644 --- 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 @@ -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/bls12-381/internal/fptower/e6.go b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower/e6.go index 8ae7216ec..128007df2 100644 --- 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 @@ -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) } @@ -126,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 { 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 index fad5940db..8779479b2 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/marshal.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/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. @@ -32,24 +32,28 @@ import ( // 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 -// -// 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. +// 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 @@ -99,8 +103,38 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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) @@ -125,6 +159,18 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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]) @@ -133,6 +179,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -153,6 +206,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -166,12 +226,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) @@ -184,6 +243,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -199,7 +265,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { } } else { var r bool - if r, err = ((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])); err != nil { + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { return } compressed[i] = !r @@ -225,7 +291,6 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return nil case *[]G2Affine: - var sliceLen uint32 sliceLen, err = dec.readUint32() if err != nil { return @@ -243,6 +308,13 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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 @@ -258,7 +330,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { } } else { var r bool - if r, err = ((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])); err != nil { + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { return } compressed[i] = !r @@ -313,6 +385,24 @@ 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 +} + +// 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)) @@ -365,6 +455,19 @@ 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()) { @@ -383,6 +486,10 @@ func (enc *Encoder) encode(v interface{}) (err error) { 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[:]) @@ -419,6 +526,17 @@ func (enc *Encoder) encode(v interface{}) (err error) { 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))) @@ -486,6 +604,10 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { 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[:]) @@ -522,6 +644,17 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { 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))) @@ -571,6 +704,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 = 48 @@ -583,7 +761,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 @@ -667,6 +845,11 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { // 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 { @@ -674,13 +857,19 @@ 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 } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +985,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er 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 isInfinity, nil } @@ -830,7 +1022,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 @@ -861,7 +1053,7 @@ 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 + // 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) @@ -920,6 +1112,11 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { // 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 { @@ -927,13 +1124,19 @@ 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 } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1063,9 +1266,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er 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 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 index 68e8b38ea..19350818f 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/multiexp.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/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. @@ -41,11 +41,12 @@ func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc. // // 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 @@ -55,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) @@ -65,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) @@ -75,7 +76,7 @@ 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") } @@ -105,29 +106,51 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.Mul C := bestC(nbPoints) nbChunks := int(computeNbChunks(C)) - // if we don't utilise all the tasks (CPU in the default case) that we could, let's see if it's worth it to split - if config.NbTasks > 1 && nbChunks < config.NbTasks { - // before spliting, let's see if we endup with more tasks than thread; - cSplit := bestC(nbPoints / 2) - nbChunksPostSplit := int(computeNbChunks(cSplit)) - nbTasksPostSplit := nbChunksPostSplit * 2 - if (nbTasksPostSplit <= config.NbTasks/2) || (nbTasksPostSplit-config.NbTasks/2) <= (config.NbTasks-nbChunks) { - // if postSplit we still have less tasks than available CPU - // or if we have more tasks BUT the difference of CPU usage is in our favor, we split. - config.NbTasks /= 2 - 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 + // 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 @@ -149,6 +172,20 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co 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-- { @@ -161,8 +198,12 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co // else what would happen is this go routine would finish much later than the others. chSplit := make(chan g1JacExtended, 2) split := n / 2 - go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split]) - go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n]) + + 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 @@ -172,7 +213,7 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co }(j) continue } - go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n]) + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) } return msmReduceChunkG1Affine(p, int(c), chChunks[:]) @@ -180,7 +221,7 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co // 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) { +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: @@ -298,11 +339,12 @@ func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc. // // 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 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 @@ -312,7 +354,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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) @@ -322,7 +364,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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) @@ -332,7 +374,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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") } @@ -362,29 +404,51 @@ func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.Mul C := bestC(nbPoints) nbChunks := int(computeNbChunks(C)) - // if we don't utilise all the tasks (CPU in the default case) that we could, let's see if it's worth it to split - if config.NbTasks > 1 && nbChunks < config.NbTasks { - // before spliting, let's see if we endup with more tasks than thread; - cSplit := bestC(nbPoints / 2) - nbChunksPostSplit := int(computeNbChunks(cSplit)) - nbTasksPostSplit := nbChunksPostSplit * 2 - if (nbTasksPostSplit <= config.NbTasks/2) || (nbTasksPostSplit-config.NbTasks/2) <= (config.NbTasks-nbChunks) { - // if postSplit we still have less tasks than available CPU - // or if we have more tasks BUT the difference of CPU usage is in our favor, we split. - config.NbTasks /= 2 - 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 + // 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 @@ -406,6 +470,20 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co 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-- { @@ -418,8 +496,12 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co // else what would happen is this go routine would finish much later than the others. chSplit := make(chan g2JacExtended, 2) split := n / 2 - go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split]) - go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n]) + + 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 @@ -429,7 +511,7 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co }(j) continue } - go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n]) + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) } return msmReduceChunkG2Affine(p, int(c), chChunks[:]) @@ -437,7 +519,7 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co // 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) { +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: @@ -552,13 +634,13 @@ type selector struct { } // return number of chunks for a given window size c -// the last chunk may be bigger to accomodate a potential carry from the NAF decomposition +// 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 accomodate a carry (from the NAF decomposition) +// 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 @@ -577,11 +659,16 @@ type chunkStat struct { } // 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 +// 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) @@ -634,7 +721,7 @@ func partitionScalars(scalars []fr.Element, c uint64, nbTasks int) ([]uint16, [] 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 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. if digit > max { digit -= (1 << c) 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 index f2fcc0573..937a43c9d 100644 --- 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 @@ -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. @@ -37,7 +37,13 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP chRes chan<- g1JacExtended, c uint64, points []G1Affine, - digits []uint16) { + 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 @@ -47,7 +53,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP // 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 immediatly + // 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. @@ -220,12 +226,18 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].ZZ.IsZero() { + 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 } @@ -353,7 +365,13 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP chRes chan<- g2JacExtended, c uint64, points []G2Affine, - digits []uint16) { + 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 @@ -363,7 +381,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP // 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 immediatly + // 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. @@ -536,12 +554,18 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].ZZ.IsZero() { + 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 } 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 index 2a2f8caa8..1b8c0e79a 100644 --- 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 @@ -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. @@ -20,7 +20,13 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, chRes chan<- g1JacExtended, c uint64, points []G1Affine, - digits []uint16) { + 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++ { @@ -33,7 +39,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add buckets[(digit>>1)-1].addMixed(&points[i]) @@ -50,12 +56,18 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { + 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 } @@ -97,7 +109,13 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, chRes chan<- g2JacExtended, c uint64, points []G2Affine, - digits []uint16) { + 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++ { @@ -110,7 +128,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add buckets[(digit>>1)-1].addMixed(&points[i]) @@ -127,12 +145,18 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { + 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 } 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 index 9a78d328d..e2c362f9b 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/pairing.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bls12-381/pairing.go @@ -77,6 +77,12 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { 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 @@ -103,7 +109,7 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { } // MillerLoop computes the multi-Miller loop -// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) +// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) = ∏ᵢ { fᵢ_{x,Qᵢ}(Pᵢ) } func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { // check input size match n := len(P) @@ -131,62 +137,114 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { qProj[k].FromAffine(&q[k]) } - var result, lines GT + 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] + } - // i == len(loopCounter) - 2 - for k := 0; k < n; k++ { - qProj[k].DoubleStep(&l1) - // line eval + // 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].AddMixedStep(&l2, &q[k]) - // line eval + // 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) // ℓ × ℓ - lines.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) // (ℓ × ℓ) × result - result.Mul(&result, &lines) + result.MulBy01245(&prodLines) } - for i := len(loopCounter) - 3; i >= 0; i-- { + // 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].DoubleStep(&l1) - // line eval + // 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].AddMixedStep(&l2, &q[k]) - // line eval + // 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) // ℓ × ℓ - lines.Mul014By014(&l1.r0, &l1.r1, &l1.r2, &l2.r0, &l2.r1, &l2.r2) + prodLines = fptower.Mul014By014(&l2.r0, &l2.r1, &l2.r2, &l1.r0, &l1.r1, &l1.r2) // (ℓ × ℓ) × result - result.Mul(&result, &lines) + 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 +// 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) { +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 @@ -226,9 +284,9 @@ func (p *g2Proj) DoubleStep(l *lineEvaluation) { } -// 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(l *lineEvaluation, a *G2Affine) { +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 @@ -262,3 +320,28 @@ func (p *g2Proj) AddMixedStep(l *lineEvaluation, a *G2Affine) { 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 976384317..f6f2990ca 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/bn254.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/bn254.go @@ -54,7 +54,8 @@ import ( // ID bn254 ID const ID = ecc.BN254 -// bCurveCoeff b coeff of the curve Y²=X³+b +// aCurveCoeff is the a coefficients of the curve Y²=X³+ax+b +var aCurveCoeff fp.Element var bCurveCoeff fp.Element // twist @@ -99,8 +100,19 @@ var endo struct { // seed x₀ of the curve var xGen big.Int -func init() { +// 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(3) // D-twist twist.A0.SetUint64(9) @@ -154,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/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/element.go index 52fb5e895..5ba388e73 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 @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/bits-and-blooms/bitset" "github.com/consensys/gnark-crypto/field/hash" "github.com/consensys/gnark-crypto/field/pool" ) @@ -231,7 +232,7 @@ func (z *Element) IsZero() bool { // IsOne returns z == 1 func (z *Element) IsOne() bool { - return (z[3] ^ 1011752739694698287 | z[2] ^ 7381016538464732716 | z[1] ^ 754611498739239741 | z[0] ^ 15230403791020821917) == 0 + return ((z[3] ^ 1011752739694698287) | (z[2] ^ 7381016538464732716) | (z[1] ^ 754611498739239741) | (z[0] ^ 15230403791020821917)) == 0 } // IsUint64 reports whether z can be represented as an uint64. @@ -333,7 +334,7 @@ func (z *Element) SetRandom() (*Element, error) { return nil, err } - // Clear unused bits in in the most signicant byte to increase probability + // Clear unused bits in in the most significant byte to increase probability // that the candidate is < q. bytes[k-1] &= uint8(int(1<= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -901,6 +902,11 @@ func (z *Element) Marshal() []byte { 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 { 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 index e75796169..acf1e44ea 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/vector.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fp/vector.go @@ -19,8 +19,13 @@ package fp import ( "bytes" "encoding/binary" + "fmt" "io" + "runtime" "strings" + "sync" + "sync/atomic" + "unsafe" ) // Vector represents a slice of Element. @@ -73,6 +78,69 @@ func (vector *Vector) WriteTo(w io.Writer) (int64, error) { 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) { @@ -130,3 +198,56 @@ func (vector Vector) Less(i, j int) bool { 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/element.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/element.go index fe3090935..cda0b2c28 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 @@ -27,6 +27,7 @@ import ( "strconv" "strings" + "github.com/bits-and-blooms/bitset" "github.com/consensys/gnark-crypto/field/hash" "github.com/consensys/gnark-crypto/field/pool" ) @@ -231,7 +232,7 @@ func (z *Element) IsZero() bool { // IsOne returns z == 1 func (z *Element) IsOne() bool { - return (z[3] ^ 1011752739694698287 | z[2] ^ 7381016538464732718 | z[1] ^ 3962172157175319849 | z[0] ^ 12436184717236109307) == 0 + return ((z[3] ^ 1011752739694698287) | (z[2] ^ 7381016538464732718) | (z[1] ^ 3962172157175319849) | (z[0] ^ 12436184717236109307)) == 0 } // IsUint64 reports whether z can be represented as an uint64. @@ -333,7 +334,7 @@ func (z *Element) SetRandom() (*Element, error) { return nil, err } - // Clear unused bits in in the most signicant byte to increase probability + // Clear unused bits in in the most significant byte to increase probability // that the candidate is < q. bytes[k-1] &= uint8(int(1<= 0; i-- { - if zeroes[i] { + if zeroes.Test(uint(i)) { continue } res[i].Mul(&res[i], &accumulator) @@ -901,6 +902,11 @@ func (z *Element) Marshal() []byte { 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 { 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 index c85a3c134..00ad8a898 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/vector.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/fr/vector.go @@ -19,8 +19,13 @@ package fr import ( "bytes" "encoding/binary" + "fmt" "io" + "runtime" "strings" + "sync" + "sync/atomic" + "unsafe" ) // Vector represents a slice of Element. @@ -73,6 +78,69 @@ func (vector *Vector) WriteTo(w io.Writer) (int64, error) { 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) { @@ -130,3 +198,56 @@ func (vector Vector) Less(i, j int) bool { 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/g1.go b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/g1.go index 718abd6f2..c03823d25 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. @@ -92,6 +92,16 @@ 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 inefficient compared to Jacobian func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { @@ -595,6 +605,10 @@ func (p *g1JacExtended) setInfinity() *g1JacExtended { 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() { @@ -988,7 +1002,7 @@ func BatchScalarMultiplicationG1(base *G1Affine, scalars []fr.Element) []G1Affin continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add p.AddMixed(&baseTableAff[(digit>>1)-1]) 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 49615c541..bb57fe175 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. @@ -81,6 +81,16 @@ 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 inefficient compared to Jacobian func (p *G2Affine) Sub(a, b *G2Affine) *G2Affine { @@ -567,6 +577,10 @@ func (p *g2JacExtended) setInfinity() *g2JacExtended { 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() { @@ -939,7 +953,7 @@ func BatchScalarMultiplicationG2(base *G2Affine, scalars []fr.Element) []G2Affin continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add p.AddAssign(&baseTable[(digit>>1)-1]) 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 index 50d40cd0e..6be3be8e1 100644 --- 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 @@ -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. @@ -20,10 +20,10 @@ 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 +// 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 { +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 @@ -112,7 +112,7 @@ func g1Sgn0(z *fp.Element) uint64 { // MapToG1 invokes the SVDW map, and guarantees that the result is in g1 func MapToG1(u fp.Element) G1Affine { - res := mapToCurve1(&u) + res := MapToCurve1(&u) return res } @@ -128,7 +128,7 @@ func EncodeToG1(msg, dst []byte) (G1Affine, error) { return res, err } - res = mapToCurve1(&u[0]) + res = MapToCurve1(&u[0]) return res, nil } @@ -143,8 +143,8 @@ func HashToG1(msg, dst []byte) (G1Affine, error) { return G1Affine{}, err } - Q0 := mapToCurve1(&u[0]) - Q1 := mapToCurve1(&u[1]) + Q0 := MapToCurve1(&u[0]) + Q1 := MapToCurve1(&u[1]) var _Q0, _Q1 G1Jac _Q0.FromAffine(&Q0) 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 index 7cf07eeac..fa81853d0 100644 --- 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 @@ -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,10 +21,10 @@ import ( "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 +// 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 { +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 @@ -143,7 +143,7 @@ func g2Sgn0(z *fptower.E2) uint64 { // MapToG2 invokes the SVDW map, and guarantees that the result is in g2 func MapToG2(u fptower.E2) G2Affine { - res := mapToCurve2(&u) + res := MapToCurve2(&u) res.ClearCofactor(&res) return res } @@ -160,7 +160,7 @@ func EncodeToG2(msg, dst []byte) (G2Affine, error) { return res, err } - res = mapToCurve2(&fptower.E2{ + res = MapToCurve2(&fptower.E2{ A0: u[0], A1: u[1], }) @@ -179,11 +179,11 @@ func HashToG2(msg, dst []byte) (G2Affine, error) { return G2Affine{}, err } - Q0 := mapToCurve2(&fptower.E2{ + Q0 := MapToCurve2(&fptower.E2{ A0: u[0], A1: u[1], }) - Q1 := mapToCurve2(&fptower.E2{ + Q1 := MapToCurve2(&fptower.E2{ A0: u[2+0], A1: u[2+1], }) 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 0ec192019..49751a939 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 6a09c11c4..c6a97081f 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 8fa8345ec..29093174b 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. @@ -36,7 +36,7 @@ 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) } @@ -99,7 +99,7 @@ func (z *E12) SetRandom() (*E12, 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 *E12) IsZero() bool { return z.C0.IsZero() && z.C1.IsZero() } @@ -230,15 +230,17 @@ func (z *E12) DecompressKarabina(x *E12) *E12 { var one E2 one.SetOne() - // g3 == 0 - if x.C1.B2.IsZero() { + 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) - // g3 != 0 - } else { + 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 @@ -302,20 +304,24 @@ func BatchDecompressKarabina(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++ { - // g3 == 0 - if x[i].C1.B2.IsZero() { + 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) - // g3 != 0 - } else { + 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 @@ -335,6 +341,10 @@ func BatchDecompressKarabina(x []E12) []E12 { 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]) @@ -640,7 +650,7 @@ 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) } @@ -713,7 +723,7 @@ func (z *E12) SetBytes(e []byte) error { return nil } -// IsInSubGroup ensures GT/E12 is in correct sugroup +// IsInSubGroup ensures GT/E12 is in correct subgroup func (z *E12) IsInSubGroup() bool { var a, b, _b E12 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 a4abaf510..78c94d2f6 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 @@ -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 65dda3992..8c16efc93 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. @@ -214,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) 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 dab250684..259609bd8 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. 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 0ce4d8333..6fe47c411 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 8ae7216ec..128007df2 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) } @@ -126,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 { 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 f980f6f16..d4a6f6eea 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 @@ -93,8 +98,38 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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) @@ -119,6 +154,18 @@ func (dec *Decoder) Decode(v interface{}) (err error) { 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]) @@ -127,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 @@ -147,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 @@ -160,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) @@ -178,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 @@ -193,7 +242,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { } } else { var r bool - if r, err = ((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])); err != nil { + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { return } compressed[i] = !r @@ -219,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 @@ -237,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 @@ -252,7 +301,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { } } else { var r bool - if r, err = ((*t)[i].unsafeSetCompressedBytes(buf[:nbBytes])); err != nil { + if r, err = (*t)[i].unsafeSetCompressedBytes(buf[:nbBytes]); err != nil { return } compressed[i] = !r @@ -307,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) @@ -359,6 +420,19 @@ 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()) { @@ -377,6 +451,10 @@ func (enc *Encoder) encode(v interface{}) (err error) { 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[:]) @@ -413,6 +491,17 @@ func (enc *Encoder) encode(v interface{}) (err error) { 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))) @@ -480,6 +569,10 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { 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[:]) @@ -516,6 +609,17 @@ func (enc *Encoder) encodeRaw(v interface{}) (err error) { 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))) @@ -565,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 @@ -577,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 @@ -670,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 @@ -787,9 +939,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er 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 isInfinity, nil } @@ -821,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 @@ -854,7 +1009,7 @@ 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 + // 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) @@ -920,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 @@ -1051,9 +1209,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er 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 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 bb4a7d6e1..9d1b71278 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. @@ -41,11 +41,12 @@ func (p *G1Affine) MultiExp(points []G1Affine, scalars []fr.Element, config ecc. // // 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 @@ -55,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) @@ -65,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) @@ -75,7 +76,7 @@ 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") } @@ -105,29 +106,51 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, config ecc.Mul C := bestC(nbPoints) nbChunks := int(computeNbChunks(C)) - // if we don't utilise all the tasks (CPU in the default case) that we could, let's see if it's worth it to split - if config.NbTasks > 1 && nbChunks < config.NbTasks { - // before spliting, let's see if we endup with more tasks than thread; - cSplit := bestC(nbPoints / 2) - nbChunksPostSplit := int(computeNbChunks(cSplit)) - nbTasksPostSplit := nbChunksPostSplit * 2 - if (nbTasksPostSplit <= config.NbTasks/2) || (nbTasksPostSplit-config.NbTasks/2) <= (config.NbTasks-nbChunks) { - // if postSplit we still have less tasks than available CPU - // or if we have more tasks BUT the difference of CPU usage is in our favor, we split. - config.NbTasks /= 2 - 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 + // 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 @@ -149,6 +172,20 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co 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-- { @@ -161,8 +198,12 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co // else what would happen is this go routine would finish much later than the others. chSplit := make(chan g1JacExtended, 2) split := n / 2 - go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split]) - go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n]) + + 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 @@ -172,7 +213,7 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co }(j) continue } - go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n]) + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) } return msmReduceChunkG1Affine(p, int(c), chChunks[:]) @@ -180,7 +221,7 @@ func _innerMsmG1(p *G1Jac, c uint64, points []G1Affine, scalars []fr.Element, co // 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) { +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: @@ -300,11 +341,12 @@ func (p *G2Affine) MultiExp(points []G2Affine, scalars []fr.Element, config ecc. // // 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 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 @@ -314,7 +356,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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) @@ -324,7 +366,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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) @@ -334,7 +376,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, 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") } @@ -364,29 +406,51 @@ func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, config ecc.Mul C := bestC(nbPoints) nbChunks := int(computeNbChunks(C)) - // if we don't utilise all the tasks (CPU in the default case) that we could, let's see if it's worth it to split - if config.NbTasks > 1 && nbChunks < config.NbTasks { - // before spliting, let's see if we endup with more tasks than thread; - cSplit := bestC(nbPoints / 2) - nbChunksPostSplit := int(computeNbChunks(cSplit)) - nbTasksPostSplit := nbChunksPostSplit * 2 - if (nbTasksPostSplit <= config.NbTasks/2) || (nbTasksPostSplit-config.NbTasks/2) <= (config.NbTasks-nbChunks) { - // if postSplit we still have less tasks than available CPU - // or if we have more tasks BUT the difference of CPU usage is in our favor, we split. - config.NbTasks /= 2 - 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 + // 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 @@ -408,6 +472,20 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co 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-- { @@ -420,8 +498,12 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co // else what would happen is this go routine would finish much later than the others. chSplit := make(chan g2JacExtended, 2) split := n / 2 - go processChunk(uint64(j), chSplit, c, points[:split], digits[j*n:(j*n)+split]) - go processChunk(uint64(j), chSplit, c, points[split:], digits[(j*n)+split:(j+1)*n]) + + 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 @@ -431,7 +513,7 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co }(j) continue } - go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n]) + go processChunk(uint64(j), chChunks[j], c, points, digits[j*n:(j+1)*n], sem) } return msmReduceChunkG2Affine(p, int(c), chChunks[:]) @@ -439,7 +521,7 @@ func _innerMsmG2(p *G2Jac, c uint64, points []G2Affine, scalars []fr.Element, co // 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) { +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: @@ -556,13 +638,13 @@ type selector struct { } // return number of chunks for a given window size c -// the last chunk may be bigger to accomodate a potential carry from the NAF decomposition +// 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 accomodate a carry (from the NAF decomposition) +// 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 @@ -581,11 +663,16 @@ type chunkStat struct { } // 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 +// 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) @@ -638,7 +725,7 @@ func partitionScalars(scalars []fr.Element, c uint64, nbTasks int) ([]uint16, [] 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 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. if digit > max { digit -= (1 << c) 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 index c0fd33431..0958526ea 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_affine.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_affine.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. @@ -37,7 +37,13 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP chRes chan<- g1JacExtended, c uint64, points []G1Affine, - digits []uint16) { + 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 @@ -47,7 +53,7 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP // 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 immediatly + // 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. @@ -220,12 +226,18 @@ func processChunkG1BatchAffine[BJE ibg1JacExtended, B ibG1Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].ZZ.IsZero() { + 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 } @@ -353,7 +365,13 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP chRes chan<- g2JacExtended, c uint64, points []G2Affine, - digits []uint16) { + 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 @@ -363,7 +381,7 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP // 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 immediatly + // 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. @@ -536,12 +554,18 @@ func processChunkG2BatchAffine[BJE ibg2JacExtended, B ibG2Affine, BS bitSet, TP total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { runningSum.addMixed(&buckets[k]) - if !bucketsJE[k].ZZ.IsZero() { + 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 } 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 index 0bd2482a9..32f728fc0 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_jacobian.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/multiexp_jacobian.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. @@ -20,7 +20,13 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, chRes chan<- g1JacExtended, c uint64, points []G1Affine, - digits []uint16) { + 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++ { @@ -33,7 +39,7 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add buckets[(digit>>1)-1].addMixed(&points[i]) @@ -50,12 +56,18 @@ func processChunkG1Jacobian[B ibg1JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { + 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 } @@ -99,7 +111,13 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, chRes chan<- g2JacExtended, c uint64, points []G2Affine, - digits []uint16) { + 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++ { @@ -112,7 +130,7 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, continue } - // if msbWindow bit is set, we need to substract + // if msbWindow bit is set, we need to subtract if digit&1 == 0 { // add buckets[(digit>>1)-1].addMixed(&points[i]) @@ -129,12 +147,18 @@ func processChunkG2Jacobian[B ibg2JacExtended](chunk uint64, runningSum.setInfinity() total.setInfinity() for k := len(buckets) - 1; k >= 0; k-- { - if !buckets[k].ZZ.IsZero() { + 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 } 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 53160c9be..ec342fe80 100644 --- a/vendor/github.com/consensys/gnark-crypto/ecc/bn254/pairing.go +++ b/vendor/github.com/consensys/gnark-crypto/ecc/bn254/pairing.go @@ -58,7 +58,7 @@ func PairingCheck(P []G1Affine, Q []G2Affine) (bool, error) { // 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) (Fuentes et al.) +// where s is the cofactor 2x₀(6x₀²+3x₀+1) func FinalExponentiation(z *GT, _z ...*GT) GT { var result GT @@ -68,56 +68,56 @@ func FinalExponentiation(z *GT, _z ...*GT) GT { result.Mul(&result, e) } - var t [4]GT + 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]) + result.FrobeniusSquare(&t[0]).Mul(&result, &t[0]) - // Hard part (up to permutation) - // 2x₀(6x₀²+3x₀+1)(p⁴-p²+1)/r + 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. variant (alg. 10) + // Fuentes et al. (alg. 6) t[0].Expt(&result). Conjugate(&t[0]) t[0].CyclotomicSquare(&t[0]) - t[2].Expt(&t[0]). - Conjugate(&t[2]) - t[1].CyclotomicSquare(&t[2]) - t[2].Mul(&t[2], &t[1]) - t[2].Mul(&t[2], &result) - t[1].Expt(&t[2]). - CyclotomicSquare(&t[1]). - Mul(&t[1], &t[2]). - Conjugate(&t[1]) - t[3].Conjugate(&t[1]) t[1].CyclotomicSquare(&t[0]) - t[1].Mul(&t[1], &result) - t[1].Conjugate(&t[1]) - t[1].Mul(&t[1], &t[3]) - t[0].Mul(&t[0], &t[1]) - t[2].Mul(&t[2], &t[1]) - t[3].FrobeniusSquare(&t[1]) + 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[3].Conjugate(&result) - t[3].Mul(&t[3], &t[0]) - t[1].FrobeniusCube(&t[3]) - t[2].Mul(&t[2], &t[1]) - t[1].Frobenius(&t[0]) - t[1].Mul(&t[1], &t[2]) + t[2].FrobeniusCube(&t[2]) + t[0].Mul(&t[2], &t[0]) - result.Set(&t[1]) - - return result + return t[0] } // MillerLoop computes the multi-Miller loop -// ∏ᵢ MillerLoop(Pᵢ, Qᵢ) +// ∏ᵢ 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) { @@ -145,50 +145,125 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { qNeg[k].Neg(&q[k]) } - var l, l0 lineEvaluation - var tmp, result GT + 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) + } + + 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) - // i == len(loopCounter) - 2 + 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) + // 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) } - for i := len(loopCounter) - 3; i >= 0; i-- { + // 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) + // 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(&l0, &q[k]) - // line evaluation - l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1.MulByElement(&l0.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[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(&l0, &qNeg[k]) - // line evaluation - l0.r0.MulByElement(&l0.r0, &p[k].Y) - l0.r1.MulByElement(&l0.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[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 { - result.MulBy034(&l.r0, &l.r1, &l.r2) + // ℓ × 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 for k := 0; k < n; k++ { //Q1 = π(Q) @@ -199,23 +274,32 @@ func MillerLoop(P []G1Affine, Q []G2Affine) (GT, error) { 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 @@ -254,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 @@ -290,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/field/generator/internal/addchain/addchain.go b/vendor/github.com/consensys/gnark-crypto/field/generator/internal/addchain/addchain.go index 408c26cf7..7dd42b183 100644 --- a/vendor/github.com/consensys/gnark-crypto/field/generator/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/internal/parallel/execute.go b/vendor/github.com/consensys/gnark-crypto/internal/parallel/execute.go index 803de3c1b..05f9a8f66 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/stretchr/objx/Taskfile.yml b/vendor/github.com/stretchr/objx/Taskfile.yml index a749ac549..7746f516d 100644 --- a/vendor/github.com/stretchr/objx/Taskfile.yml +++ b/vendor/github.com/stretchr/objx/Taskfile.yml @@ -25,6 +25,6 @@ tasks: - go test -race ./... test-coverage: - desc: Runs go tests and calucates test coverage + desc: Runs go tests and calculates test coverage cmds: - go test -race -coverprofile=c.out ./... diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go index fa1245b18..2924cf3a1 100644 --- a/vendor/github.com/stretchr/testify/assert/assertions.go +++ b/vendor/github.com/stretchr/testify/assert/assertions.go @@ -8,7 +8,6 @@ import ( "fmt" "math" "os" - "path/filepath" "reflect" "regexp" "runtime" @@ -141,12 +140,11 @@ func CallerInfo() []string { } parts := strings.Split(file, "/") - file = parts[len(parts)-1] if len(parts) > 1 { + filename := parts[len(parts)-1] dir := parts[len(parts)-2] - if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { - path, _ := filepath.Abs(file) - callers = append(callers, fmt.Sprintf("%s:%d", path, line)) + if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" { + callers = append(callers, fmt.Sprintf("%s:%d", file, line)) } } @@ -530,7 +528,7 @@ func isNil(object interface{}) bool { []reflect.Kind{ reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, - reflect.Ptr, reflect.Slice}, + reflect.Ptr, reflect.Slice, reflect.UnsafePointer}, kind) if isNilableKind && value.IsNil() { @@ -818,49 +816,44 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok return true // we consider nil to be equal to the nil set } - defer func() { - if e := recover(); e != nil { - ok = false - } - }() - listKind := reflect.TypeOf(list).Kind() - subsetKind := reflect.TypeOf(subset).Kind() - if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } + subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } - subsetValue := reflect.ValueOf(subset) if subsetKind == reflect.Map && listKind == reflect.Map { - listValue := reflect.ValueOf(list) - subsetKeys := subsetValue.MapKeys() + subsetMap := reflect.ValueOf(subset) + actualMap := reflect.ValueOf(list) - for i := 0; i < len(subsetKeys); i++ { - subsetKey := subsetKeys[i] - subsetElement := subsetValue.MapIndex(subsetKey).Interface() - listElement := listValue.MapIndex(subsetKey).Interface() + for _, k := range subsetMap.MapKeys() { + ev := subsetMap.MapIndex(k) + av := actualMap.MapIndex(k) - if !ObjectsAreEqual(subsetElement, listElement) { - return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, subsetElement), msgAndArgs...) + if !av.IsValid() { + return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) + } + if !ObjectsAreEqual(ev.Interface(), av.Interface()) { + return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...) } } return true } - for i := 0; i < subsetValue.Len(); i++ { - element := subsetValue.Index(i).Interface() + subsetList := reflect.ValueOf(subset) + for i := 0; i < subsetList.Len(); i++ { + element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { - return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...) } if !found { - return Fail(t, fmt.Sprintf("\"%s\" does not contain \"%s\"", list, element), msgAndArgs...) + return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...) } } @@ -879,34 +872,28 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...) } - defer func() { - if e := recover(); e != nil { - ok = false - } - }() - listKind := reflect.TypeOf(list).Kind() - subsetKind := reflect.TypeOf(subset).Kind() - if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...) } + subsetKind := reflect.TypeOf(subset).Kind() if subsetKind != reflect.Array && subsetKind != reflect.Slice && listKind != reflect.Map { return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...) } - subsetValue := reflect.ValueOf(subset) if subsetKind == reflect.Map && listKind == reflect.Map { - listValue := reflect.ValueOf(list) - subsetKeys := subsetValue.MapKeys() + subsetMap := reflect.ValueOf(subset) + actualMap := reflect.ValueOf(list) - for i := 0; i < len(subsetKeys); i++ { - subsetKey := subsetKeys[i] - subsetElement := subsetValue.MapIndex(subsetKey).Interface() - listElement := listValue.MapIndex(subsetKey).Interface() + for _, k := range subsetMap.MapKeys() { + ev := subsetMap.MapIndex(k) + av := actualMap.MapIndex(k) - if !ObjectsAreEqual(subsetElement, listElement) { + if !av.IsValid() { + return true + } + if !ObjectsAreEqual(ev.Interface(), av.Interface()) { return true } } @@ -914,8 +901,9 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...) } - for i := 0; i < subsetValue.Len(); i++ { - element := subsetValue.Index(i).Interface() + subsetList := reflect.ValueOf(subset) + for i := 0; i < subsetList.Len(); i++ { + element := subsetList.Index(i).Interface() ok, found := containsElement(list, element) if !ok { return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", list), msgAndArgs...) diff --git a/vendor/github.com/stretchr/testify/mock/mock.go b/vendor/github.com/stretchr/testify/mock/mock.go index f0af8246c..e6ff8dfeb 100644 --- a/vendor/github.com/stretchr/testify/mock/mock.go +++ b/vendor/github.com/stretchr/testify/mock/mock.go @@ -218,16 +218,22 @@ func (c *Call) Unset() *Call { foundMatchingCall := false - for i, call := range c.Parent.ExpectedCalls { + // in-place filter slice for calls to be removed - iterate from 0'th to last skipping unnecessary ones + var index int // write index + for _, call := range c.Parent.ExpectedCalls { if call.Method == c.Method { _, diffCount := call.Arguments.Diff(c.Arguments) if diffCount == 0 { foundMatchingCall = true - // Remove from ExpectedCalls - c.Parent.ExpectedCalls = append(c.Parent.ExpectedCalls[:i], c.Parent.ExpectedCalls[i+1:]...) + // Remove from ExpectedCalls - just skip it + continue } } + c.Parent.ExpectedCalls[index] = call + index++ } + // trim slice up to last copied index + c.Parent.ExpectedCalls = c.Parent.ExpectedCalls[:index] if !foundMatchingCall { unlockOnce.Do(c.unlock) diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go index aeb73f81a..5577c0f93 100644 --- a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go +++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go @@ -50,7 +50,7 @@ func (ih InvalidHashPrefixError) Error() string { type InvalidCostError int func (ic InvalidCostError) Error() string { - return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost)) + return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), MinCost, MaxCost) } const ( @@ -82,11 +82,20 @@ type hashed struct { minor byte } +// ErrPasswordTooLong is returned when the password passed to +// GenerateFromPassword is too long (i.e. > 72 bytes). +var ErrPasswordTooLong = errors.New("bcrypt: password length exceeds 72 bytes") + // GenerateFromPassword returns the bcrypt hash of the password at the given // cost. If the cost given is less than MinCost, the cost will be set to // DefaultCost, instead. Use CompareHashAndPassword, as defined in this package, // to compare the returned hashed password with its cleartext version. +// GenerateFromPassword does not accept passwords longer than 72 bytes, which +// is the longest password bcrypt will operate on. func GenerateFromPassword(password []byte, cost int) ([]byte, error) { + if len(password) > 72 { + return nil, ErrPasswordTooLong + } p, err := newFromPassword(password, cost) if err != nil { return nil, err diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1.go index 3a1674a1e..6fc2838a3 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/asn1.go +++ b/vendor/golang.org/x/crypto/cryptobyte/asn1.go @@ -264,36 +264,35 @@ func (s *String) ReadASN1Boolean(out *bool) bool { return true } -var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem() - // ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does -// not point to an integer or to a big.Int, it panics. It reports whether the -// read was successful. +// not point to an integer, to a big.Int, or to a []byte it panics. Only +// positive and zero values can be decoded into []byte, and they are returned as +// big-endian binary values that share memory with s. Positive values will have +// no leading zeroes, and zero will be returned as a single zero byte. +// ReadASN1Integer reports whether the read was successful. func (s *String) ReadASN1Integer(out interface{}) bool { - if reflect.TypeOf(out).Kind() != reflect.Ptr { - panic("out is not a pointer") - } - switch reflect.ValueOf(out).Elem().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + switch out := out.(type) { + case *int, *int8, *int16, *int32, *int64: var i int64 if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) { return false } reflect.ValueOf(out).Elem().SetInt(i) return true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + case *uint, *uint8, *uint16, *uint32, *uint64: var u uint64 if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) { return false } reflect.ValueOf(out).Elem().SetUint(u) return true - case reflect.Struct: - if reflect.TypeOf(out).Elem() == bigIntType { - return s.readASN1BigInt(out.(*big.Int)) - } + case *big.Int: + return s.readASN1BigInt(out) + case *[]byte: + return s.readASN1Bytes(out) + default: + panic("out does not point to an integer type") } - panic("out does not point to an integer type") } func checkASN1Integer(bytes []byte) bool { @@ -333,6 +332,21 @@ func (s *String) readASN1BigInt(out *big.Int) bool { return true } +func (s *String) readASN1Bytes(out *[]byte) bool { + var bytes String + if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) { + return false + } + if bytes[0]&0x80 == 0x80 { + return false + } + for len(bytes) > 1 && bytes[0] == 0 { + bytes = bytes[1:] + } + *out = bytes + return true +} + func (s *String) readASN1Int64(out *int64) bool { var bytes String if !s.ReadASN1(&bytes, asn1.INTEGER) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) { @@ -417,6 +431,14 @@ func (s *String) readBase128Int(out *int) bool { } ret <<= 7 b := s.read(1)[0] + + // ITU-T X.690, section 8.19.2: + // The subidentifier shall be encoded in the fewest possible octets, + // that is, the leading octet of the subidentifier shall not have the value 0x80. + if i == 0 && b == 0x80 { + return false + } + ret |= int(b & 0x7f) if b&0x80 == 0 { *out = ret @@ -532,7 +554,7 @@ func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { return false } - paddingBits := uint8(bytes[0]) + paddingBits := bytes[0] bytes = bytes[1:] if paddingBits > 7 || len(bytes) == 0 && paddingBits != 0 || @@ -545,7 +567,7 @@ func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool { return true } -// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It is +// ReadASN1BitStringAsBytes decodes an ASN.1 BIT STRING into out and advances. It is // an error if the BIT STRING is not a whole number of bytes. It reports // whether the read was successful. func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool { @@ -554,7 +576,7 @@ func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool { return false } - paddingBits := uint8(bytes[0]) + paddingBits := bytes[0] if paddingBits != 0 { return false } @@ -654,34 +676,27 @@ func (s *String) SkipOptionalASN1(tag asn1.Tag) bool { return s.ReadASN1(&unused, tag) } -// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER -// explicitly tagged with tag into out and advances. If no element with a -// matching tag is present, it writes defaultValue into out instead. If out -// does not point to an integer or to a big.Int, it panics. It reports -// whether the read was successful. +// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER explicitly +// tagged with tag into out and advances. If no element with a matching tag is +// present, it writes defaultValue into out instead. Otherwise, it behaves like +// ReadASN1Integer. func (s *String) ReadOptionalASN1Integer(out interface{}, tag asn1.Tag, defaultValue interface{}) bool { - if reflect.TypeOf(out).Kind() != reflect.Ptr { - panic("out is not a pointer") - } var present bool var i String if !s.ReadOptionalASN1(&i, &present, tag) { return false } if !present { - switch reflect.ValueOf(out).Elem().Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + switch out.(type) { + case *int, *int8, *int16, *int32, *int64, + *uint, *uint8, *uint16, *uint32, *uint64, *[]byte: reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue)) - case reflect.Struct: - if reflect.TypeOf(out).Elem() != bigIntType { - panic("invalid integer type") - } - if reflect.TypeOf(defaultValue).Kind() != reflect.Ptr || - reflect.TypeOf(defaultValue).Elem() != bigIntType { + case *big.Int: + if defaultValue, ok := defaultValue.(*big.Int); ok { + out.(*big.Int).Set(defaultValue) + } else { panic("out points to big.Int, but defaultValue does not") } - out.(*big.Int).Set(defaultValue.(*big.Int)) default: panic("invalid integer type") } diff --git a/vendor/golang.org/x/crypto/cryptobyte/builder.go b/vendor/golang.org/x/crypto/cryptobyte/builder.go index 2a90c592d..c05ac7d16 100644 --- a/vendor/golang.org/x/crypto/cryptobyte/builder.go +++ b/vendor/golang.org/x/crypto/cryptobyte/builder.go @@ -303,9 +303,9 @@ func (b *Builder) add(bytes ...byte) { b.result = append(b.result, bytes...) } -// Unwrite rolls back n bytes written directly to the Builder. An attempt by a -// child builder passed to a continuation to unwrite bytes from its parent will -// panic. +// Unwrite rolls back non-negative n bytes written directly to the Builder. +// An attempt by a child builder passed to a continuation to unwrite bytes +// from its parent will panic. func (b *Builder) Unwrite(n int) { if b.err != nil { return @@ -317,6 +317,9 @@ func (b *Builder) Unwrite(n int) { if length < 0 { panic("cryptobyte: internal error") } + if n < 0 { + panic("cryptobyte: attempted to unwrite negative number of bytes") + } if n > length { panic("cryptobyte: attempted to unwrite more than was written") } diff --git a/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go index 7499e3fb6..05de9cc2c 100644 --- a/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go +++ b/vendor/golang.org/x/crypto/pkcs12/internal/rc2/rc2.go @@ -14,6 +14,7 @@ package rc2 import ( "crypto/cipher" "encoding/binary" + "math/bits" ) // The rc2 block size in bytes @@ -80,10 +81,6 @@ func expandKey(key []byte, t1 int) [64]uint16 { return k } -func rotl16(x uint16, b uint) uint16 { - return (x >> (16 - b)) | (x << b) -} - func (c *rc2Cipher) Encrypt(dst, src []byte) { r0 := binary.LittleEndian.Uint16(src[0:]) @@ -96,22 +93,22 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) { for j <= 16 { // mix r0 r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) - r0 = rotl16(r0, 1) + r0 = bits.RotateLeft16(r0, 1) j++ // mix r1 r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) - r1 = rotl16(r1, 2) + r1 = bits.RotateLeft16(r1, 2) j++ // mix r2 r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) - r2 = rotl16(r2, 3) + r2 = bits.RotateLeft16(r2, 3) j++ // mix r3 r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) - r3 = rotl16(r3, 5) + r3 = bits.RotateLeft16(r3, 5) j++ } @@ -124,22 +121,22 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) { for j <= 40 { // mix r0 r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) - r0 = rotl16(r0, 1) + r0 = bits.RotateLeft16(r0, 1) j++ // mix r1 r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) - r1 = rotl16(r1, 2) + r1 = bits.RotateLeft16(r1, 2) j++ // mix r2 r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) - r2 = rotl16(r2, 3) + r2 = bits.RotateLeft16(r2, 3) j++ // mix r3 r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) - r3 = rotl16(r3, 5) + r3 = bits.RotateLeft16(r3, 5) j++ } @@ -152,22 +149,22 @@ func (c *rc2Cipher) Encrypt(dst, src []byte) { for j <= 60 { // mix r0 r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) - r0 = rotl16(r0, 1) + r0 = bits.RotateLeft16(r0, 1) j++ // mix r1 r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) - r1 = rotl16(r1, 2) + r1 = bits.RotateLeft16(r1, 2) j++ // mix r2 r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) - r2 = rotl16(r2, 3) + r2 = bits.RotateLeft16(r2, 3) j++ // mix r3 r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) - r3 = rotl16(r3, 5) + r3 = bits.RotateLeft16(r3, 5) j++ } @@ -188,22 +185,22 @@ func (c *rc2Cipher) Decrypt(dst, src []byte) { for j >= 44 { // unmix r3 - r3 = rotl16(r3, 16-5) + r3 = bits.RotateLeft16(r3, 16-5) r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) j-- // unmix r2 - r2 = rotl16(r2, 16-3) + r2 = bits.RotateLeft16(r2, 16-3) r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) j-- // unmix r1 - r1 = rotl16(r1, 16-2) + r1 = bits.RotateLeft16(r1, 16-2) r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) j-- // unmix r0 - r0 = rotl16(r0, 16-1) + r0 = bits.RotateLeft16(r0, 16-1) r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) j-- } @@ -215,22 +212,22 @@ func (c *rc2Cipher) Decrypt(dst, src []byte) { for j >= 20 { // unmix r3 - r3 = rotl16(r3, 16-5) + r3 = bits.RotateLeft16(r3, 16-5) r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) j-- // unmix r2 - r2 = rotl16(r2, 16-3) + r2 = bits.RotateLeft16(r2, 16-3) r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) j-- // unmix r1 - r1 = rotl16(r1, 16-2) + r1 = bits.RotateLeft16(r1, 16-2) r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) j-- // unmix r0 - r0 = rotl16(r0, 16-1) + r0 = bits.RotateLeft16(r0, 16-1) r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) j-- @@ -243,22 +240,22 @@ func (c *rc2Cipher) Decrypt(dst, src []byte) { for j >= 0 { // unmix r3 - r3 = rotl16(r3, 16-5) + r3 = bits.RotateLeft16(r3, 16-5) r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) j-- // unmix r2 - r2 = rotl16(r2, 16-3) + r2 = bits.RotateLeft16(r2, 16-3) r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) j-- // unmix r1 - r1 = rotl16(r1, 16-2) + r1 = bits.RotateLeft16(r1, 16-2) r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) j-- // unmix r0 - r0 = rotl16(r0, 16-1) + r0 = bits.RotateLeft16(r0, 16-1) r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) j-- diff --git a/vendor/golang.org/x/crypto/sha3/keccakf.go b/vendor/golang.org/x/crypto/sha3/keccakf.go index 0f4ae8bac..e5faa375c 100644 --- a/vendor/golang.org/x/crypto/sha3/keccakf.go +++ b/vendor/golang.org/x/crypto/sha3/keccakf.go @@ -7,6 +7,8 @@ package sha3 +import "math/bits" + // rc stores the round constants for use in the ι step. var rc = [24]uint64{ 0x0000000000000001, @@ -60,13 +62,13 @@ func keccakF1600(a *[25]uint64) { bc0 = a[0] ^ d0 t = a[6] ^ d1 - bc1 = t<<44 | t>>(64-44) + bc1 = bits.RotateLeft64(t, 44) t = a[12] ^ d2 - bc2 = t<<43 | t>>(64-43) + bc2 = bits.RotateLeft64(t, 43) t = a[18] ^ d3 - bc3 = t<<21 | t>>(64-21) + bc3 = bits.RotateLeft64(t, 21) t = a[24] ^ d4 - bc4 = t<<14 | t>>(64-14) + bc4 = bits.RotateLeft64(t, 14) a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i] a[6] = bc1 ^ (bc3 &^ bc2) a[12] = bc2 ^ (bc4 &^ bc3) @@ -74,15 +76,15 @@ func keccakF1600(a *[25]uint64) { a[24] = bc4 ^ (bc1 &^ bc0) t = a[10] ^ d0 - bc2 = t<<3 | t>>(64-3) + bc2 = bits.RotateLeft64(t, 3) t = a[16] ^ d1 - bc3 = t<<45 | t>>(64-45) + bc3 = bits.RotateLeft64(t, 45) t = a[22] ^ d2 - bc4 = t<<61 | t>>(64-61) + bc4 = bits.RotateLeft64(t, 61) t = a[3] ^ d3 - bc0 = t<<28 | t>>(64-28) + bc0 = bits.RotateLeft64(t, 28) t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) + bc1 = bits.RotateLeft64(t, 20) a[10] = bc0 ^ (bc2 &^ bc1) a[16] = bc1 ^ (bc3 &^ bc2) a[22] = bc2 ^ (bc4 &^ bc3) @@ -90,15 +92,15 @@ func keccakF1600(a *[25]uint64) { a[9] = bc4 ^ (bc1 &^ bc0) t = a[20] ^ d0 - bc4 = t<<18 | t>>(64-18) + bc4 = bits.RotateLeft64(t, 18) t = a[1] ^ d1 - bc0 = t<<1 | t>>(64-1) + bc0 = bits.RotateLeft64(t, 1) t = a[7] ^ d2 - bc1 = t<<6 | t>>(64-6) + bc1 = bits.RotateLeft64(t, 6) t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) + bc2 = bits.RotateLeft64(t, 25) t = a[19] ^ d4 - bc3 = t<<8 | t>>(64-8) + bc3 = bits.RotateLeft64(t, 8) a[20] = bc0 ^ (bc2 &^ bc1) a[1] = bc1 ^ (bc3 &^ bc2) a[7] = bc2 ^ (bc4 &^ bc3) @@ -106,15 +108,15 @@ func keccakF1600(a *[25]uint64) { a[19] = bc4 ^ (bc1 &^ bc0) t = a[5] ^ d0 - bc1 = t<<36 | t>>(64-36) + bc1 = bits.RotateLeft64(t, 36) t = a[11] ^ d1 - bc2 = t<<10 | t>>(64-10) + bc2 = bits.RotateLeft64(t, 10) t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) + bc3 = bits.RotateLeft64(t, 15) t = a[23] ^ d3 - bc4 = t<<56 | t>>(64-56) + bc4 = bits.RotateLeft64(t, 56) t = a[4] ^ d4 - bc0 = t<<27 | t>>(64-27) + bc0 = bits.RotateLeft64(t, 27) a[5] = bc0 ^ (bc2 &^ bc1) a[11] = bc1 ^ (bc3 &^ bc2) a[17] = bc2 ^ (bc4 &^ bc3) @@ -122,15 +124,15 @@ func keccakF1600(a *[25]uint64) { a[4] = bc4 ^ (bc1 &^ bc0) t = a[15] ^ d0 - bc3 = t<<41 | t>>(64-41) + bc3 = bits.RotateLeft64(t, 41) t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) + bc4 = bits.RotateLeft64(t, 2) t = a[2] ^ d2 - bc0 = t<<62 | t>>(64-62) + bc0 = bits.RotateLeft64(t, 62) t = a[8] ^ d3 - bc1 = t<<55 | t>>(64-55) + bc1 = bits.RotateLeft64(t, 55) t = a[14] ^ d4 - bc2 = t<<39 | t>>(64-39) + bc2 = bits.RotateLeft64(t, 39) a[15] = bc0 ^ (bc2 &^ bc1) a[21] = bc1 ^ (bc3 &^ bc2) a[2] = bc2 ^ (bc4 &^ bc3) @@ -151,13 +153,13 @@ func keccakF1600(a *[25]uint64) { bc0 = a[0] ^ d0 t = a[16] ^ d1 - bc1 = t<<44 | t>>(64-44) + bc1 = bits.RotateLeft64(t, 44) t = a[7] ^ d2 - bc2 = t<<43 | t>>(64-43) + bc2 = bits.RotateLeft64(t, 43) t = a[23] ^ d3 - bc3 = t<<21 | t>>(64-21) + bc3 = bits.RotateLeft64(t, 21) t = a[14] ^ d4 - bc4 = t<<14 | t>>(64-14) + bc4 = bits.RotateLeft64(t, 14) a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1] a[16] = bc1 ^ (bc3 &^ bc2) a[7] = bc2 ^ (bc4 &^ bc3) @@ -165,15 +167,15 @@ func keccakF1600(a *[25]uint64) { a[14] = bc4 ^ (bc1 &^ bc0) t = a[20] ^ d0 - bc2 = t<<3 | t>>(64-3) + bc2 = bits.RotateLeft64(t, 3) t = a[11] ^ d1 - bc3 = t<<45 | t>>(64-45) + bc3 = bits.RotateLeft64(t, 45) t = a[2] ^ d2 - bc4 = t<<61 | t>>(64-61) + bc4 = bits.RotateLeft64(t, 61) t = a[18] ^ d3 - bc0 = t<<28 | t>>(64-28) + bc0 = bits.RotateLeft64(t, 28) t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) + bc1 = bits.RotateLeft64(t, 20) a[20] = bc0 ^ (bc2 &^ bc1) a[11] = bc1 ^ (bc3 &^ bc2) a[2] = bc2 ^ (bc4 &^ bc3) @@ -181,15 +183,15 @@ func keccakF1600(a *[25]uint64) { a[9] = bc4 ^ (bc1 &^ bc0) t = a[15] ^ d0 - bc4 = t<<18 | t>>(64-18) + bc4 = bits.RotateLeft64(t, 18) t = a[6] ^ d1 - bc0 = t<<1 | t>>(64-1) + bc0 = bits.RotateLeft64(t, 1) t = a[22] ^ d2 - bc1 = t<<6 | t>>(64-6) + bc1 = bits.RotateLeft64(t, 6) t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) + bc2 = bits.RotateLeft64(t, 25) t = a[4] ^ d4 - bc3 = t<<8 | t>>(64-8) + bc3 = bits.RotateLeft64(t, 8) a[15] = bc0 ^ (bc2 &^ bc1) a[6] = bc1 ^ (bc3 &^ bc2) a[22] = bc2 ^ (bc4 &^ bc3) @@ -197,15 +199,15 @@ func keccakF1600(a *[25]uint64) { a[4] = bc4 ^ (bc1 &^ bc0) t = a[10] ^ d0 - bc1 = t<<36 | t>>(64-36) + bc1 = bits.RotateLeft64(t, 36) t = a[1] ^ d1 - bc2 = t<<10 | t>>(64-10) + bc2 = bits.RotateLeft64(t, 10) t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) + bc3 = bits.RotateLeft64(t, 15) t = a[8] ^ d3 - bc4 = t<<56 | t>>(64-56) + bc4 = bits.RotateLeft64(t, 56) t = a[24] ^ d4 - bc0 = t<<27 | t>>(64-27) + bc0 = bits.RotateLeft64(t, 27) a[10] = bc0 ^ (bc2 &^ bc1) a[1] = bc1 ^ (bc3 &^ bc2) a[17] = bc2 ^ (bc4 &^ bc3) @@ -213,15 +215,15 @@ func keccakF1600(a *[25]uint64) { a[24] = bc4 ^ (bc1 &^ bc0) t = a[5] ^ d0 - bc3 = t<<41 | t>>(64-41) + bc3 = bits.RotateLeft64(t, 41) t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) + bc4 = bits.RotateLeft64(t, 2) t = a[12] ^ d2 - bc0 = t<<62 | t>>(64-62) + bc0 = bits.RotateLeft64(t, 62) t = a[3] ^ d3 - bc1 = t<<55 | t>>(64-55) + bc1 = bits.RotateLeft64(t, 55) t = a[19] ^ d4 - bc2 = t<<39 | t>>(64-39) + bc2 = bits.RotateLeft64(t, 39) a[5] = bc0 ^ (bc2 &^ bc1) a[21] = bc1 ^ (bc3 &^ bc2) a[12] = bc2 ^ (bc4 &^ bc3) @@ -242,13 +244,13 @@ func keccakF1600(a *[25]uint64) { bc0 = a[0] ^ d0 t = a[11] ^ d1 - bc1 = t<<44 | t>>(64-44) + bc1 = bits.RotateLeft64(t, 44) t = a[22] ^ d2 - bc2 = t<<43 | t>>(64-43) + bc2 = bits.RotateLeft64(t, 43) t = a[8] ^ d3 - bc3 = t<<21 | t>>(64-21) + bc3 = bits.RotateLeft64(t, 21) t = a[19] ^ d4 - bc4 = t<<14 | t>>(64-14) + bc4 = bits.RotateLeft64(t, 14) a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2] a[11] = bc1 ^ (bc3 &^ bc2) a[22] = bc2 ^ (bc4 &^ bc3) @@ -256,15 +258,15 @@ func keccakF1600(a *[25]uint64) { a[19] = bc4 ^ (bc1 &^ bc0) t = a[15] ^ d0 - bc2 = t<<3 | t>>(64-3) + bc2 = bits.RotateLeft64(t, 3) t = a[1] ^ d1 - bc3 = t<<45 | t>>(64-45) + bc3 = bits.RotateLeft64(t, 45) t = a[12] ^ d2 - bc4 = t<<61 | t>>(64-61) + bc4 = bits.RotateLeft64(t, 61) t = a[23] ^ d3 - bc0 = t<<28 | t>>(64-28) + bc0 = bits.RotateLeft64(t, 28) t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) + bc1 = bits.RotateLeft64(t, 20) a[15] = bc0 ^ (bc2 &^ bc1) a[1] = bc1 ^ (bc3 &^ bc2) a[12] = bc2 ^ (bc4 &^ bc3) @@ -272,15 +274,15 @@ func keccakF1600(a *[25]uint64) { a[9] = bc4 ^ (bc1 &^ bc0) t = a[5] ^ d0 - bc4 = t<<18 | t>>(64-18) + bc4 = bits.RotateLeft64(t, 18) t = a[16] ^ d1 - bc0 = t<<1 | t>>(64-1) + bc0 = bits.RotateLeft64(t, 1) t = a[2] ^ d2 - bc1 = t<<6 | t>>(64-6) + bc1 = bits.RotateLeft64(t, 6) t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) + bc2 = bits.RotateLeft64(t, 25) t = a[24] ^ d4 - bc3 = t<<8 | t>>(64-8) + bc3 = bits.RotateLeft64(t, 8) a[5] = bc0 ^ (bc2 &^ bc1) a[16] = bc1 ^ (bc3 &^ bc2) a[2] = bc2 ^ (bc4 &^ bc3) @@ -288,15 +290,15 @@ func keccakF1600(a *[25]uint64) { a[24] = bc4 ^ (bc1 &^ bc0) t = a[20] ^ d0 - bc1 = t<<36 | t>>(64-36) + bc1 = bits.RotateLeft64(t, 36) t = a[6] ^ d1 - bc2 = t<<10 | t>>(64-10) + bc2 = bits.RotateLeft64(t, 10) t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) + bc3 = bits.RotateLeft64(t, 15) t = a[3] ^ d3 - bc4 = t<<56 | t>>(64-56) + bc4 = bits.RotateLeft64(t, 56) t = a[14] ^ d4 - bc0 = t<<27 | t>>(64-27) + bc0 = bits.RotateLeft64(t, 27) a[20] = bc0 ^ (bc2 &^ bc1) a[6] = bc1 ^ (bc3 &^ bc2) a[17] = bc2 ^ (bc4 &^ bc3) @@ -304,15 +306,15 @@ func keccakF1600(a *[25]uint64) { a[14] = bc4 ^ (bc1 &^ bc0) t = a[10] ^ d0 - bc3 = t<<41 | t>>(64-41) + bc3 = bits.RotateLeft64(t, 41) t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) + bc4 = bits.RotateLeft64(t, 2) t = a[7] ^ d2 - bc0 = t<<62 | t>>(64-62) + bc0 = bits.RotateLeft64(t, 62) t = a[18] ^ d3 - bc1 = t<<55 | t>>(64-55) + bc1 = bits.RotateLeft64(t, 55) t = a[4] ^ d4 - bc2 = t<<39 | t>>(64-39) + bc2 = bits.RotateLeft64(t, 39) a[10] = bc0 ^ (bc2 &^ bc1) a[21] = bc1 ^ (bc3 &^ bc2) a[7] = bc2 ^ (bc4 &^ bc3) @@ -333,13 +335,13 @@ func keccakF1600(a *[25]uint64) { bc0 = a[0] ^ d0 t = a[1] ^ d1 - bc1 = t<<44 | t>>(64-44) + bc1 = bits.RotateLeft64(t, 44) t = a[2] ^ d2 - bc2 = t<<43 | t>>(64-43) + bc2 = bits.RotateLeft64(t, 43) t = a[3] ^ d3 - bc3 = t<<21 | t>>(64-21) + bc3 = bits.RotateLeft64(t, 21) t = a[4] ^ d4 - bc4 = t<<14 | t>>(64-14) + bc4 = bits.RotateLeft64(t, 14) a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3] a[1] = bc1 ^ (bc3 &^ bc2) a[2] = bc2 ^ (bc4 &^ bc3) @@ -347,15 +349,15 @@ func keccakF1600(a *[25]uint64) { a[4] = bc4 ^ (bc1 &^ bc0) t = a[5] ^ d0 - bc2 = t<<3 | t>>(64-3) + bc2 = bits.RotateLeft64(t, 3) t = a[6] ^ d1 - bc3 = t<<45 | t>>(64-45) + bc3 = bits.RotateLeft64(t, 45) t = a[7] ^ d2 - bc4 = t<<61 | t>>(64-61) + bc4 = bits.RotateLeft64(t, 61) t = a[8] ^ d3 - bc0 = t<<28 | t>>(64-28) + bc0 = bits.RotateLeft64(t, 28) t = a[9] ^ d4 - bc1 = t<<20 | t>>(64-20) + bc1 = bits.RotateLeft64(t, 20) a[5] = bc0 ^ (bc2 &^ bc1) a[6] = bc1 ^ (bc3 &^ bc2) a[7] = bc2 ^ (bc4 &^ bc3) @@ -363,15 +365,15 @@ func keccakF1600(a *[25]uint64) { a[9] = bc4 ^ (bc1 &^ bc0) t = a[10] ^ d0 - bc4 = t<<18 | t>>(64-18) + bc4 = bits.RotateLeft64(t, 18) t = a[11] ^ d1 - bc0 = t<<1 | t>>(64-1) + bc0 = bits.RotateLeft64(t, 1) t = a[12] ^ d2 - bc1 = t<<6 | t>>(64-6) + bc1 = bits.RotateLeft64(t, 6) t = a[13] ^ d3 - bc2 = t<<25 | t>>(64-25) + bc2 = bits.RotateLeft64(t, 25) t = a[14] ^ d4 - bc3 = t<<8 | t>>(64-8) + bc3 = bits.RotateLeft64(t, 8) a[10] = bc0 ^ (bc2 &^ bc1) a[11] = bc1 ^ (bc3 &^ bc2) a[12] = bc2 ^ (bc4 &^ bc3) @@ -379,15 +381,15 @@ func keccakF1600(a *[25]uint64) { a[14] = bc4 ^ (bc1 &^ bc0) t = a[15] ^ d0 - bc1 = t<<36 | t>>(64-36) + bc1 = bits.RotateLeft64(t, 36) t = a[16] ^ d1 - bc2 = t<<10 | t>>(64-10) + bc2 = bits.RotateLeft64(t, 10) t = a[17] ^ d2 - bc3 = t<<15 | t>>(64-15) + bc3 = bits.RotateLeft64(t, 15) t = a[18] ^ d3 - bc4 = t<<56 | t>>(64-56) + bc4 = bits.RotateLeft64(t, 56) t = a[19] ^ d4 - bc0 = t<<27 | t>>(64-27) + bc0 = bits.RotateLeft64(t, 27) a[15] = bc0 ^ (bc2 &^ bc1) a[16] = bc1 ^ (bc3 &^ bc2) a[17] = bc2 ^ (bc4 &^ bc3) @@ -395,15 +397,15 @@ func keccakF1600(a *[25]uint64) { a[19] = bc4 ^ (bc1 &^ bc0) t = a[20] ^ d0 - bc3 = t<<41 | t>>(64-41) + bc3 = bits.RotateLeft64(t, 41) t = a[21] ^ d1 - bc4 = t<<2 | t>>(64-2) + bc4 = bits.RotateLeft64(t, 2) t = a[22] ^ d2 - bc0 = t<<62 | t>>(64-62) + bc0 = bits.RotateLeft64(t, 62) t = a[23] ^ d3 - bc1 = t<<55 | t>>(64-55) + bc1 = bits.RotateLeft64(t, 55) t = a[24] ^ d4 - bc2 = t<<39 | t>>(64-39) + bc2 = bits.RotateLeft64(t, 39) a[20] = bc0 ^ (bc2 &^ bc1) a[21] = bc1 ^ (bc3 &^ bc2) a[22] = bc2 ^ (bc4 &^ bc3) diff --git a/vendor/golang.org/x/net/html/doc.go b/vendor/golang.org/x/net/html/doc.go index 822ed42a0..2466ae3d9 100644 --- a/vendor/golang.org/x/net/html/doc.go +++ b/vendor/golang.org/x/net/html/doc.go @@ -92,6 +92,27 @@ example, to process each anchor node in depth-first order: The relevant specifications include: https://html.spec.whatwg.org/multipage/syntax.html and https://html.spec.whatwg.org/multipage/syntax.html#tokenization + +# Security Considerations + +Care should be taken when parsing and interpreting HTML, whether full documents +or fragments, within the framework of the HTML specification, especially with +regard to untrusted inputs. + +This package provides both a tokenizer and a parser, which implement the +tokenization, and tokenization and tree construction stages of the WHATWG HTML +parsing specification respectively. While the tokenizer parses and normalizes +individual HTML tokens, only the parser constructs the DOM tree from the +tokenized HTML, as described in the tree construction stage of the +specification, dynamically modifying or extending the docuemnt's DOM tree. + +If your use case requires semantically well-formed HTML documents, as defined by +the WHATWG specification, the parser should be used rather than the tokenizer. + +In security contexts, if trust decisions are being made using the tokenized or +parsed content, the input must be re-serialized (for instance by using Render or +Token.String) in order for those trust decisions to hold, as the process of +tokenization or parsing may alter the content. */ package html // import "golang.org/x/net/html" diff --git a/vendor/golang.org/x/net/html/escape.go b/vendor/golang.org/x/net/html/escape.go index d85613962..04c6bec21 100644 --- a/vendor/golang.org/x/net/html/escape.go +++ b/vendor/golang.org/x/net/html/escape.go @@ -193,6 +193,87 @@ func lower(b []byte) []byte { return b } +// escapeComment is like func escape but escapes its input bytes less often. +// Per https://github.com/golang/go/issues/58246 some HTML comments are (1) +// meaningful and (2) contain angle brackets that we'd like to avoid escaping +// unless we have to. +// +// "We have to" includes the '&' byte, since that introduces other escapes. +// +// It also includes those bytes (not including EOF) that would otherwise end +// the comment. Per the summary table at the bottom of comment_test.go, this is +// the '>' byte that, per above, we'd like to avoid escaping unless we have to. +// +// Studying the summary table (and T actions in its '>' column) closely, we +// only need to escape in states 43, 44, 49, 51 and 52. State 43 is at the +// start of the comment data. State 52 is after a '!'. The other three states +// are after a '-'. +// +// Our algorithm is thus to escape every '&' and to escape '>' if and only if: +// - The '>' is after a '!' or '-' (in the unescaped data) or +// - The '>' is at the start of the comment data (after the opening ""); err != nil { diff --git a/vendor/golang.org/x/net/html/token.go b/vendor/golang.org/x/net/html/token.go index 50f7c6aac..5c2a1f4ef 100644 --- a/vendor/golang.org/x/net/html/token.go +++ b/vendor/golang.org/x/net/html/token.go @@ -110,7 +110,7 @@ func (t Token) String() string { case SelfClosingTagToken: return "<" + t.tagString() + "/>" case CommentToken: - return "" + return "" case DoctypeToken: return "" } @@ -598,10 +598,10 @@ scriptDataDoubleEscapeEnd: // readComment reads the next comment token starting with "