├── .github ├── CODEOWNERS └── workflows │ └── ci-tests.yml ├── .gitignore ├── LICENSE ├── PERFORMANCE.md ├── README.md ├── curve ├── bench_test.go ├── constants.go ├── constants_tables.go ├── constants_test.go ├── constants_u32.go ├── constants_u32_test.go ├── constants_u64.go ├── constants_u64_test.go ├── curve.go ├── edwards.go ├── edwards_precomputation.go ├── edwards_test.go ├── edwards_vector_amd64.go ├── edwards_vector_amd64.s ├── edwards_vector_amd64_test.go ├── edwards_vector_generic.go ├── edwards_vector_test.go ├── models.go ├── montgomery.go ├── montgomery_test.go ├── ristretto.go ├── ristretto_precomputation.go ├── ristretto_test.go ├── ristretto_vectors_test.go ├── scalar │ ├── constants_u32.go │ ├── constants_u64.go │ ├── sc_minimal.go │ ├── scalar.go │ ├── scalar_test.go │ ├── scalar_u32.go │ ├── scalar_u32_test.go │ ├── scalar_u64.go │ ├── scalar_u64_test.go │ ├── scalar_unpacked.go │ └── scalar_unpacked_test.go ├── scalar_mul_abglsv_pornin.go ├── scalar_mul_abglsv_pornin_test.go ├── scalar_mul_basepoint.go ├── scalar_mul_pippenger.go ├── scalar_mul_pippenger_test.go ├── scalar_mul_straus.go ├── scalar_mul_variable_base.go ├── scalar_mul_vartime_double_base.go ├── window.go ├── window_amd64.go ├── window_amd64.s └── window_generic.go ├── go.mod ├── go.sum ├── internal ├── asm │ └── amd64 │ │ ├── common.go │ │ ├── edwards_vector.go │ │ ├── field_u64.go │ │ ├── gen.sh │ │ ├── go.mod │ │ ├── go.sum │ │ └── window.go ├── disalloweq │ └── disalloweq.go ├── elligator │ ├── constants_test.go │ ├── constants_u32.go │ ├── constants_u64.go │ ├── elligator2.go │ └── elligator2_test.go ├── field │ ├── constants_u32.go │ ├── constants_u64.go │ ├── field.go │ ├── field_test.go │ ├── field_u32.go │ ├── field_u64.go │ ├── field_u64_amd64.go │ ├── field_u64_amd64.s │ ├── field_u64_amd64_test.go │ └── field_u64_generic.go ├── lattice │ ├── big_int.go │ ├── int128.go │ ├── lattice_reduction.go │ └── lattice_reduction_test.go ├── scalar128 │ └── scalar128.go ├── strobe │ ├── keccakf.go │ ├── keccakf_amd64.go │ ├── keccakf_amd64.s │ ├── strobe.go │ └── strobe_test.go ├── subtle │ └── subtle.go ├── testhelpers │ └── helpers.go ├── toolchain │ ├── compiler_is_gc.go │ ├── constraints.go │ └── version_is_recent.go └── zeroreader │ └── zeroreader.go └── primitives ├── ed25519 ├── batch_verify.go ├── batch_verify_test.go ├── ed25519.go ├── ed25519_precomputation.go ├── ed25519_test.go ├── ed25519ph_test.go ├── ed25519vectors_test.go ├── example_batch_test.go ├── example_options_test.go ├── example_test.go ├── extra │ ├── cache │ │ ├── cache.go │ │ ├── cache_test.go │ │ └── lru.go │ └── ecvrf │ │ ├── ecvrf.go │ │ └── ecvrf_test.go ├── speccheck_test.go ├── testdata │ ├── ed25519vectors.json.gz │ ├── eddsa_test.json.gz │ ├── rfc8032_ctx.json.gz │ ├── sign.input.gz │ ├── speccheck_cases.json.gz │ └── zip215.json.gz ├── wycheproof_test.go └── zip215_test.go ├── h2c ├── expand_message.go ├── h2c.go ├── testdata │ ├── edwards25519_XMD_SHA-512_ELL2_NU_.json.gz │ ├── edwards25519_XMD_SHA-512_ELL2_RO_.json.gz │ ├── expand_message_xmd_SHA256_256.json.gz │ ├── expand_message_xmd_SHA256_38.json.gz │ ├── expand_message_xmd_SHA512_38.json.gz │ ├── expand_message_xof_SHAKE128_256.json.gz │ ├── expand_message_xof_SHAKE128_36.json.gz │ └── expand_message_xof_SHAKE256_36.json.gz └── vectors_test.go ├── merlin ├── merlin.go └── merlin_test.go ├── sr25519 ├── batch_verify.go ├── batch_verify_test.go ├── context.go ├── doc.go ├── example_test.go ├── keys.go ├── keys_test.go ├── sign.go └── sign_test.go └── x25519 ├── example_test.go ├── testdata └── x25519_test.json.gz ├── vectors_test.go ├── wycheproof_test.go ├── x25519.go └── x25519_test.go /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @Yawning 2 | -------------------------------------------------------------------------------- /.github/workflows/ci-tests.yml: -------------------------------------------------------------------------------- 1 | # NOTE: This name appears in GitHub's Checks API and in workflow's status badge. 2 | name: ci-tests 3 | 4 | permissions: 5 | contents: read 6 | 7 | # Trigger the workflow when: 8 | on: 9 | # A push occurs to one of the matched branches. 10 | push: 11 | branches: 12 | - master 13 | # Or when a pull request event occurs for a pull request against one of the 14 | # matched branches. 15 | pull_request: 16 | branches: 17 | - master 18 | 19 | jobs: 20 | tests: 21 | # NOTE: This name appears in GitHub's Checks API. 22 | name: tests 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Checkout code 26 | uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 27 | - name: Set up Go 1.18 28 | uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f # v3.3.0 29 | with: 30 | go-version: "1.18.x" 31 | - name: Run 32 bit tests 32 | run: | 33 | go test ./... -tags=force32bit 34 | GOARCH=arm go build ./... 35 | - name: Run 64 bit tests 36 | run: go test ./... -tags=force64bit 37 | - name: Run purego tests 38 | run: go test ./... -tags=purego 39 | - name: Run golangci-lint 40 | uses: golangci/golangci-lint-action@537aa1903e5d359d0b27dbc19ddd22c5087f3fbc # v3.2.0 41 | with: 42 | version: v1.49 43 | skip-pkg-cache: true 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | Copyright (c) 2014, 2015, 2016, 2019 The Go Authors. All rights reserved. 4 | Copyright (c) 2017, 2019 George Tankersley. All rights reserved. 5 | Copyright (c) 2019-2020 Web 3 Foundation. All rights reserved. 6 | Copyright (c) 2020 Jack Grigg. All rights reserved. 7 | Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are 11 | met: 12 | 13 | 1. Redistributions of source code must retain the above copyright 14 | notice, this list of conditions and the following disclaimer. 15 | 16 | 2. Redistributions in binary form must reproduce the above copyright 17 | notice, this list of conditions and the following disclaimer in the 18 | documentation and/or other materials provided with the distribution. 19 | 20 | 3. Neither the name of the copyright holder nor the names of its 21 | contributors may be used to endorse or promote products derived from 22 | this software without specific prior written permission. 23 | 24 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 25 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 27 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 29 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 30 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 31 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 32 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 33 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /curve/constants.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package curve 33 | 34 | import "github.com/oasisprotocol/curve25519-voi/internal/field" 35 | 36 | const ( 37 | // CompressedPointSize is the size of a compressed point in bytes. 38 | CompressedPointSize = 32 39 | 40 | // MontgomeryPointSize is the size of the u-coordinate of a point on 41 | // the Montgomery form in bytes. 42 | MontgomeryPointSize = 32 43 | 44 | // RistrettoUniformSize is the size of the uniformly random bytes 45 | // required to construct a random Ristretto point. 46 | RistrettoUniformSize = 64 47 | ) 48 | 49 | var ( 50 | // ED25519_BASEPOINT_COMPRESSED is the Ed25519 basepoint, in 51 | // CompressedEdwardsY format. 52 | ED25519_BASEPOINT_COMPRESSED = &CompressedEdwardsY{ 53 | 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 54 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 55 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 56 | 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 57 | } 58 | 59 | // X25519_BASEPOINT is the X25519 basepoint, in MontgomeryPoint 60 | // format. 61 | X25519_BASEPOINT = &MontgomeryPoint{ 62 | 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 64 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 66 | } 67 | 68 | // RISTRETTO_BASEPOINT_COMPRESED is the Ristretto basepoint, in 69 | // CompressedRistretto format. 70 | RISTRETTO_BASEPOINT_COMPRESSED = &CompressedRistretto{ 71 | 0xe2, 0xf2, 0xae, 0x0a, 0x6a, 0xbc, 0x4e, 0x71, 72 | 0xa8, 0x84, 0xa9, 0x61, 0xc5, 0x00, 0x51, 0x5f, 73 | 0x58, 0xe3, 0x0b, 0x6a, 0xa5, 0x82, 0xdd, 0x8d, 74 | 0xb6, 0xa6, 0x59, 0x45, 0xe0, 0x8d, 0x2d, 0x76, 75 | } 76 | 77 | // RISTRETTO_BASEPOINT_POINT is the Ristretto basepoint, in 78 | // RistrettoPoint format. 79 | RISTRETTO_BASEPOINT_POINT = &RistrettoPoint{ 80 | inner: *ED25519_BASEPOINT_POINT, 81 | } 82 | 83 | // RISTRETTO_BASEPOINT_TABLE is the Ristretto basepoint, as a 84 | // RistrettoBasepointTable for scalar multiplication. 85 | RISTRETTO_BASEPOINT_TABLE = &RistrettoBasepointTable{ 86 | inner: *ED25519_BASEPOINT_TABLE, 87 | } 88 | ) 89 | 90 | func newEdwardsPoint(X, Y, Z, T field.Element) *EdwardsPoint { 91 | return &EdwardsPoint{ 92 | edwardsPointInner{ 93 | X: X, 94 | Y: Y, 95 | Z: Z, 96 | T: T, 97 | }, 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /curve/constants_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package curve 33 | 34 | import ( 35 | "testing" 36 | 37 | "github.com/oasisprotocol/curve25519-voi/internal/field" 38 | ) 39 | 40 | func TestConstants(t *testing.T) { 41 | t.Run("BShl128", testConstantsBShl128) 42 | t.Run("EightTorsion", testConstantsEightTorsion) 43 | t.Run("FourTorsion", testConstantsFourTorsion) 44 | t.Run("TwoTorsion", testConstantsTwoTorsion) 45 | t.Run("SqrtAdMinusOne", testConstantsSqrtAdMinusOne) 46 | t.Run("D/VsRatio", testConstantsDVsRatio) 47 | t.Run("AffineBasepointOddLookupTable", testConstantsAffineBasepointOddLookupTable) 48 | t.Run("AffineBasepointOddShl128LookupTable", testConstantsAffineBasepointOddShl128LookupTable) 49 | // ED25519_BASEPOINT_TABLE is checked by `testEdwardsBasepointTableNew`. 50 | } 51 | 52 | func testConstantsBShl128(t *testing.T) { 53 | var p EdwardsPoint 54 | p.mulByPow2(ED25519_BASEPOINT_POINT, 128) 55 | 56 | if p.Equal(constB_SHL_128) != 1 { 57 | t.Fatalf("B_SHL_128 != 2^128 B (Got: %v)", constB_SHL_128) 58 | } 59 | } 60 | 61 | func testConstantsEightTorsion(t *testing.T) { 62 | for i, torsionPoint := range EIGHT_TORSION { 63 | var q EdwardsPoint 64 | q.mulByPow2(torsionPoint, 3) 65 | if !q.debugIsValid() { 66 | t.Fatalf("EIGHT_TORSION[%d].mulByPow2(3).debugIsValid() != true", i) 67 | } 68 | if !q.IsIdentity() { 69 | t.Fatalf("EIGHT_TORSION[%d].mulByPow2(3).IsIdentity() != true", i) 70 | } 71 | } 72 | } 73 | 74 | func testConstantsFourTorsion(t *testing.T) { 75 | for i, torsionPoint := range EIGHT_TORSION { 76 | if i%2 != 0 { 77 | continue 78 | } 79 | var q EdwardsPoint 80 | q.mulByPow2(torsionPoint, 2) 81 | if !q.debugIsValid() { 82 | t.Fatalf("EIGHT_TORSION[%d].mulByPow2(2).debugIsValid() != true", i) 83 | } 84 | if !q.IsIdentity() { 85 | t.Fatalf("EIGHT_TORSION[%d].mulByPow2(2).IsIdentity() != true", i) 86 | } 87 | } 88 | } 89 | 90 | func testConstantsTwoTorsion(t *testing.T) { 91 | for i, torsionPoint := range EIGHT_TORSION { 92 | if i%4 != 0 { 93 | continue 94 | } 95 | var q EdwardsPoint 96 | q.mulByPow2(torsionPoint, 1) 97 | if !q.debugIsValid() { 98 | t.Fatalf("EIGHT_TORSION[%d].mulByPow2(1).debugIsValid() != true", i) 99 | } 100 | if !q.IsIdentity() { 101 | t.Fatalf("EIGHT_TORSION[%d].mulByPow2(1).IsIdentity() != true", i) 102 | } 103 | } 104 | } 105 | 106 | func testConstantsSqrtAdMinusOne(t *testing.T) { 107 | var a field.Element 108 | a.MinusOne() 109 | 110 | var adMinusOne field.Element 111 | adMinusOne.Mul(&a, &constEDWARDS_D) 112 | adMinusOne.Add(&adMinusOne, &a) 113 | 114 | var shouldBeAdMinusOne field.Element 115 | shouldBeAdMinusOne.Square(&constSQRT_AD_MINUS_ONE) 116 | 117 | if shouldBeAdMinusOne.Equal(&adMinusOne) != 1 { 118 | t.Fatalf("should_be_ad_minus_one != ad_minus_one (Got: %v, %v)", shouldBeAdMinusOne, adMinusOne) 119 | } 120 | } 121 | 122 | func testConstantsAffineBasepointOddLookupTable(t *testing.T) { 123 | gen := newAffineNielsPointNafLookupTable(ED25519_BASEPOINT_POINT) 124 | 125 | for i, pt := range gen { 126 | entry := constAFFINE_ODD_MULTIPLES_OF_BASEPOINT[i] 127 | if !entry.testEqual(&pt) { 128 | t.Fatalf("constAFFINE_ODD_MULTIPLES_OF_BASEPOINT[%d] != pt (Got: %v)", i, entry) 129 | } 130 | } 131 | } 132 | 133 | func testConstantsAffineBasepointOddShl128LookupTable(t *testing.T) { 134 | gen := newAffineNielsPointNafLookupTable(constB_SHL_128) 135 | 136 | for i, pt := range gen { 137 | entry := constAFFINE_ODD_MULTIPLES_OF_B_SHL_128[i] 138 | if !entry.testEqual(&pt) { 139 | t.Fatalf("constAFFINE_ODD_MULTIPLES_B_SHL_128[%d] != pt (Got: %v)", i, entry) 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /curve/constants_u32_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | //go:build (386 || arm || mips || mipsle || wasm || mips64le || mips64 || riscv64 || loong64 || force32bit) && !force64bit 33 | 34 | package curve 35 | 36 | import ( 37 | "testing" 38 | 39 | "github.com/oasisprotocol/curve25519-voi/internal/field" 40 | ) 41 | 42 | func testConstantsDVsRatio(t *testing.T) { 43 | // Test that d = -121665/121666. 44 | a := field.NewElement2625(121665, 0, 0, 0, 0, 0, 0, 0, 0, 0) 45 | a.Neg(&a) 46 | bInv := field.NewElement2625(121666, 0, 0, 0, 0, 0, 0, 0, 0, 0) 47 | bInv.Invert(&bInv) 48 | 49 | var d, d2 field.Element 50 | d.Mul(&a, &bInv) 51 | d2.Add(&d, &d) 52 | 53 | if d.Equal(&constEDWARDS_D) != 1 { 54 | t.Fatalf("d != EDWARDS_D (Got: %v)", d) 55 | } 56 | if d2.Equal(&constEDWARDS_D2) != 1 { 57 | t.Fatalf("d2 != EDWARDS_D2 (Got: %v)", d2) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /curve/constants_u64_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | //go:build (amd64 || arm64 || ppc64le || ppc64 || s390x || force64bit) && !force32bit 33 | 34 | package curve 35 | 36 | import ( 37 | "testing" 38 | 39 | "github.com/oasisprotocol/curve25519-voi/internal/field" 40 | ) 41 | 42 | func testConstantsDVsRatio(t *testing.T) { 43 | // Test that d = -121665/121666. 44 | a := field.NewElement51(121665, 0, 0, 0, 0) 45 | a.Neg(&a) 46 | bInv := field.NewElement51(121666, 0, 0, 0, 0) 47 | bInv.Invert(&bInv) 48 | 49 | var d, d2 field.Element 50 | d.Mul(&a, &bInv) 51 | d2.Add(&d, &d) 52 | 53 | if d.Equal(&constEDWARDS_D) != 1 { 54 | t.Fatalf("d != EDWARDS_D (Got: %v)", d) 55 | } 56 | if d2.Equal(&constEDWARDS_D2) != 1 { 57 | t.Fatalf("d2 != EDWARDS_D2 (Got: %v)", d2) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /curve/curve.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Package curve provides group operations on the Edwards and Montgomery 31 | // forms of Curve25519, and on the prime-order Ristretto group. 32 | // 33 | // Most users should NOT use this package. 34 | package curve 35 | -------------------------------------------------------------------------------- /curve/edwards_precomputation.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package curve 31 | 32 | import "github.com/oasisprotocol/curve25519-voi/curve/scalar" 33 | 34 | // ExpandedEdwardsPoint is an Edwards point stored in an expanded 35 | // representation for the purpose of accelerating scalar point 36 | // multiply operations. 37 | // 38 | // The default value is NOT valid and MUST only be used as a receiver. 39 | type ExpandedEdwardsPoint struct { 40 | point EdwardsPoint 41 | 42 | inner *projectiveNielsPointNafLookupTable 43 | innerVector *cachedPointNafLookupTable 44 | 45 | // TODO/perf: Consider adding support for Pippenger's algorithm, 46 | // though that requires a table with 64 -> 256 entries depending 47 | // on the `w` used, which is a massive waste of space if the 48 | // multiscalar multiply is never called with a large number of 49 | // terms. 50 | } 51 | 52 | // Point returns the Edwards point represented by the expanded point. 53 | func (ep *ExpandedEdwardsPoint) Point() *EdwardsPoint { 54 | var p EdwardsPoint 55 | return p.Set(&ep.point) 56 | } 57 | 58 | // SetEdwardsPoint sets the expanded point to the Edwards point. 59 | func (ep *ExpandedEdwardsPoint) SetEdwardsPoint(p *EdwardsPoint) *ExpandedEdwardsPoint { 60 | var negP EdwardsPoint 61 | negP.Neg(p) 62 | 63 | switch supportsVectorizedEdwards { 64 | case true: 65 | tbl := newCachedPointNafLookupTable(p) 66 | ep.inner = nil 67 | ep.innerVector = &tbl 68 | default: 69 | tbl := newProjectiveNielsPointNafLookupTable(p) 70 | ep.inner = &tbl 71 | ep.innerVector = nil 72 | } 73 | 74 | ep.point.Set(p) 75 | 76 | return ep 77 | } 78 | 79 | // NewExpandedEdwardsPoint creates an expanded representation of an 80 | // Edwards point. 81 | func NewExpandedEdwardsPoint(p *EdwardsPoint) *ExpandedEdwardsPoint { 82 | var ep ExpandedEdwardsPoint 83 | return ep.SetEdwardsPoint(p) 84 | } 85 | 86 | // ExpandedDoubleScalarMulBasepointVartime sets `p = (aA + bB)` in variable-time, 87 | // where B is the Ed25519 basepoint, and returns p. 88 | func (p *EdwardsPoint) ExpandedDoubleScalarMulBasepointVartime(a *scalar.Scalar, A *ExpandedEdwardsPoint, b *scalar.Scalar) *EdwardsPoint { 89 | return expandedEdwardsDoubleScalarMulBasepointVartime(p, a, A, b) 90 | } 91 | 92 | // ExpandedTripleScalarMulBasepoint sets `p = [delta a]A + [delta b]B - [delta]C` 93 | // in variable-time, where delta is a value invertible mod ell, which 94 | // is selected internally to this method. 95 | func (p *EdwardsPoint) ExpandedTripleScalarMulBasepointVartime(a *scalar.Scalar, A *ExpandedEdwardsPoint, b *scalar.Scalar, C *EdwardsPoint) *EdwardsPoint { 96 | return expandedEdwardsMulAbglsvPorninVartime(p, a, A, b, C) 97 | } 98 | 99 | // ExpandedMultiscalarMulVartime sets `p = staticScalars[0] * staticPoints[0] + 100 | // ... + staticScalars[n] * staticPoints[n] + dynamicScalars[0] * 101 | // dynamicPoints[0] + ... + dynamicScalars[n] * dynamicPoints[n]` in variable-time, 102 | // and returns p. 103 | // 104 | // WARNING: This function will panic if `len(staticScalars) != len(staticPoints)` 105 | // or `len(dynamicScalars) != len(dynamicPoints)`. 106 | func (p *EdwardsPoint) ExpandedMultiscalarMulVartime(staticScalars []*scalar.Scalar, staticPoints []*ExpandedEdwardsPoint, dynamicScalars []*scalar.Scalar, dynamicPoints []*EdwardsPoint) *EdwardsPoint { 107 | staticSize, dynamicSize := len(staticScalars), len(dynamicScalars) 108 | if staticSize != len(staticPoints) { 109 | panic("curve/edwards: len(staticScalars) != len(staticPoints)") 110 | } 111 | if dynamicSize != len(dynamicPoints) { 112 | panic("curve/edwards: len(dynamicScalars) != len(dynamicPoints)") 113 | } 114 | 115 | switch { 116 | case staticSize+dynamicSize > mulPippengerThreshold: 117 | return expandedEdwardsMultiscalarMulPippengerVartime(p, staticScalars, staticPoints, dynamicScalars, dynamicPoints) 118 | default: 119 | return expandedEdwardsMultiscalarMulStrausVartime(p, staticScalars, staticPoints, dynamicScalars, dynamicPoints) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /curve/edwards_vector_generic.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build !amd64 || purego || force32bit 31 | 32 | package curve 33 | 34 | import ( 35 | "fmt" 36 | 37 | "github.com/oasisprotocol/curve25519-voi/internal/disalloweq" 38 | ) 39 | 40 | // Stub type definitions filled with my inner urges to panic, to allow 41 | // the non-vector/vector code to be somewhat consolidated to prevent 42 | // an explosion of files. 43 | 44 | const supportsVectorizedEdwards = false 45 | 46 | var ( 47 | errVectorNotSupported = fmt.Errorf("curve: vector backend not supported") 48 | 49 | // These are not actually used, since the vector code is never called 50 | // but need to be defined. 51 | constEXTENDEDPOINT_IDENTITY extendedPoint 52 | constVECTOR_ODD_MULTIPLES_OF_BASEPOINT *cachedPointNafLookupTable8 53 | constVECTOR_ODD_MULTIPLES_OF_B_SHL_128 *cachedPointNafLookupTable8 54 | ) 55 | 56 | type extendedPoint struct { 57 | disalloweq.DisallowEqual //nolint:unused 58 | } 59 | 60 | func (p *EdwardsPoint) setExtended(ep *extendedPoint) *EdwardsPoint { 61 | panic(errVectorNotSupported) 62 | } 63 | 64 | func (p *EdwardsPoint) setCached(cp *cachedPoint) *EdwardsPoint { 65 | panic(errVectorNotSupported) 66 | } 67 | 68 | func (p *extendedPoint) SetEdwards(ep *EdwardsPoint) *extendedPoint { 69 | panic(errVectorNotSupported) 70 | } 71 | 72 | func (p *extendedPoint) Identity() *extendedPoint { 73 | panic(errVectorNotSupported) 74 | } 75 | 76 | func (p *extendedPoint) Double(t *extendedPoint) *extendedPoint { 77 | panic(errVectorNotSupported) 78 | } 79 | 80 | func (p *extendedPoint) MulByPow2(t *extendedPoint, k uint) *extendedPoint { 81 | panic(errVectorNotSupported) 82 | } 83 | 84 | func (p *extendedPoint) AddExtendedCached(a *extendedPoint, b *cachedPoint) *extendedPoint { 85 | panic(errVectorNotSupported) 86 | } 87 | 88 | func (p *extendedPoint) SubExtendedCached(a *extendedPoint, b *cachedPoint) *extendedPoint { 89 | panic(errVectorNotSupported) 90 | } 91 | 92 | type cachedPoint struct { 93 | disalloweq.DisallowEqual //nolint:unused 94 | } 95 | 96 | func (p *cachedPoint) SetExtended(ep *extendedPoint) *cachedPoint { 97 | panic(errVectorNotSupported) 98 | } 99 | 100 | func (p *cachedPoint) ConditionalNegate(choice int) { 101 | panic(errVectorNotSupported) 102 | } 103 | -------------------------------------------------------------------------------- /curve/edwards_vector_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package curve 33 | 34 | import ( 35 | "testing" 36 | 37 | "github.com/oasisprotocol/curve25519-voi/curve/scalar" 38 | ) 39 | 40 | func TestVector(t *testing.T) { 41 | if !supportsVectorizedEdwards { 42 | t.Skipf("Vector backend not supported") 43 | } 44 | 45 | t.Run("ExtendedPoint", func(t *testing.T) { 46 | t.Run("AddSubCached", testVecAddSubCached) 47 | t.Run("Double", testVecDoubleExtended) 48 | }) 49 | } 50 | 51 | func testVecDoubleExtended(t *testing.T) { 52 | doubleEdwardsSerial := func(p *EdwardsPoint) *EdwardsPoint { 53 | var out EdwardsPoint 54 | return out.double(p) 55 | } 56 | 57 | doubleEdwardsVector := func(p *EdwardsPoint) *EdwardsPoint { 58 | var pExtended extendedPoint 59 | pExtended.Double(pExtended.SetEdwards(p)) 60 | 61 | var out EdwardsPoint 62 | return out.setExtended(&pExtended) 63 | } 64 | 65 | for _, v := range []struct { 66 | p *EdwardsPoint 67 | n string 68 | }{ 69 | {ED25519_BASEPOINT_POINT, "B"}, 70 | {edwardsPointTestIdentity, "id"}, 71 | {testPoint_kB(), "([k]B)"}, 72 | } { 73 | pS := doubleEdwardsSerial(v.p) 74 | pV := doubleEdwardsVector(v.p) 75 | 76 | if pS.Equal(pV) != 1 { 77 | t.Fatalf("[2]%s incorrect (Got: %v)", v.n, pV) 78 | } 79 | } 80 | } 81 | 82 | func testVecAddSubCached(t *testing.T) { 83 | addSubEdwardsVector := func(a, b *EdwardsPoint, isSub bool) *EdwardsPoint { 84 | var ( 85 | aExtended, bExtended, abExtended extendedPoint 86 | bCached cachedPoint 87 | ) 88 | aExtended.SetEdwards(a) 89 | bCached.SetExtended(bExtended.SetEdwards(b)) 90 | 91 | switch isSub { 92 | case false: 93 | abExtended.AddExtendedCached(&aExtended, &bCached) 94 | case true: 95 | abExtended.SubExtendedCached(&aExtended, &bCached) 96 | } 97 | 98 | var out EdwardsPoint 99 | return out.setExtended(&abExtended) 100 | } 101 | 102 | addEdwardsVector := func(a, b *EdwardsPoint) *EdwardsPoint { 103 | return addSubEdwardsVector(a, b, false) 104 | } 105 | 106 | subEdwardsVector := func(a, b *EdwardsPoint) *EdwardsPoint { 107 | return addSubEdwardsVector(a, b, true) 108 | } 109 | 110 | addEdwardsSerial := func(a, b *EdwardsPoint) *EdwardsPoint { 111 | var out EdwardsPoint 112 | out.Add(a, b) 113 | return &out 114 | } 115 | 116 | subEdwardsSerial := func(a, b *EdwardsPoint) *EdwardsPoint { 117 | var out EdwardsPoint 118 | out.Sub(a, b) 119 | return &out 120 | } 121 | 122 | for _, v := range []struct { 123 | a, b *EdwardsPoint 124 | an, bn string 125 | }{ 126 | {edwardsPointTestIdentity, edwardsPointTestIdentity, "id", "id"}, 127 | {edwardsPointTestIdentity, ED25519_BASEPOINT_POINT, "id", "B"}, 128 | {ED25519_BASEPOINT_POINT, ED25519_BASEPOINT_POINT, "B", "B"}, 129 | {ED25519_BASEPOINT_POINT, testPoint_kB(), "B", "([k]B)"}, 130 | } { 131 | sS := addEdwardsSerial(v.a, v.b) 132 | sV := addEdwardsVector(v.a, v.b) 133 | if sS.Equal(sV) != 1 { 134 | t.Fatalf("%s + %s incorrect (Got: %v)", v.an, v.bn, sV) 135 | } 136 | 137 | dS := subEdwardsSerial(v.a, v.b) 138 | dV := subEdwardsVector(v.a, v.b) 139 | if dS.Equal(dV) != 1 { 140 | t.Fatalf("%s - %s incorrect (Got: %v)", v.an, v.bn, dV) 141 | } 142 | } 143 | } 144 | 145 | func testPoint_kB() *EdwardsPoint { 146 | var p EdwardsPoint 147 | return p.MulBasepoint(ED25519_BASEPOINT_TABLE, scalar.NewFromUint64(8475983829)) 148 | } 149 | -------------------------------------------------------------------------------- /curve/montgomery_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package curve 33 | 34 | import ( 35 | "testing" 36 | 37 | "github.com/oasisprotocol/curve25519-voi/internal/field" 38 | ) 39 | 40 | func TestMontgomery(t *testing.T) { 41 | t.Run("EdwardsPointFromMontgomery", testMontgomeryEdwardsPointFromMontgomery) 42 | t.Run("EdwardsPointFromMontgomery/RejectsTwist", testMontgomeryEdwardsPointFromMontgomeryRejectsTwist) 43 | t.Run("FromEdwards", testMontgomeryFromEdwards) 44 | t.Run("Equal", testMontgomeryEqual) 45 | t.Run("Mul", testMontgomeryMul) 46 | } 47 | 48 | func testMontgomeryEdwardsPointFromMontgomery(t *testing.T) { 49 | var p EdwardsPoint 50 | if _, err := p.SetMontgomery(X25519_BASEPOINT, 0); err != nil { 51 | t.Fatalf("SetMontgomery(X25519_BASEPOINT, 0)") 52 | } 53 | if p.Equal(ED25519_BASEPOINT_POINT) != 1 { 54 | t.Fatalf("SetMontgomery(X25519_BASEPOINT, 0) != ED25519_BASEPOINT_POINT (Got: %v)", p) 55 | } 56 | 57 | var negBasepoint EdwardsPoint 58 | negBasepoint.Neg(ED25519_BASEPOINT_POINT) 59 | if _, err := p.SetMontgomery(X25519_BASEPOINT, 1); err != nil { 60 | t.Fatalf("SetMontgomery(X25519_BASEPOINT, 0)") 61 | } 62 | if p.Equal(&negBasepoint) != 1 { 63 | t.Fatalf("SetMontgomery-X25519_BASEPOINT, 1) != -ED25519_BASEPOINT_POINT (Got: %v)", p) 64 | } 65 | } 66 | 67 | func testMontgomeryEdwardsPointFromMontgomeryRejectsTwist(t *testing.T) { 68 | // u = 2 corresponds to a point on the twist. 69 | var pM MontgomeryPoint 70 | _ = field.Two.ToBytes(pM[:]) 71 | 72 | var p EdwardsPoint 73 | if _, err := p.SetMontgomery(&pM, 0); err == nil { 74 | t.Fatalf("SetMontgomery(2, 0) != error (Got: %v)", p) 75 | } 76 | 77 | // u = -1 corresponds to a point on the twist, but should be 78 | // checked explicitly because it's an exceptional point for the 79 | // birational map. For instance, libsignal will accept it. 80 | _ = field.MinusOne.ToBytes(pM[:]) 81 | if _, err := p.SetMontgomery(&pM, 0); err == nil { 82 | t.Fatalf("SetMontgomery(-1, 0) != error (Got: %v)", p) 83 | } 84 | } 85 | 86 | func testMontgomeryFromEdwards(t *testing.T) { 87 | var p MontgomeryPoint 88 | p.SetEdwards(ED25519_BASEPOINT_POINT) 89 | if p.Equal(X25519_BASEPOINT) != 1 { 90 | t.Fatalf("FromEdwards(ED25519_BASEPOINT_POINT) != X25519_BASEPOINT (Got: %v)", p) 91 | } 92 | } 93 | 94 | func testMontgomeryEqual(t *testing.T) { 95 | u18Bytes := [MontgomeryPointSize]byte{18} 96 | u18UnreducedBytes := [MontgomeryPointSize]byte{ 97 | 255, 255, 255, 255, 255, 255, 255, 255, 98 | 255, 255, 255, 255, 255, 255, 255, 255, 99 | 255, 255, 255, 255, 255, 255, 255, 255, 100 | 255, 255, 255, 255, 255, 255, 255, 255, 101 | } 102 | 103 | u18, u18Unreduced := MontgomeryPoint(u18Bytes), MontgomeryPoint(u18UnreducedBytes) 104 | if u18.Equal(&u18Unreduced) != 1 { 105 | t.Fatalf("u18 != u18Unreduced") 106 | } 107 | } 108 | 109 | func testMontgomeryMul(t *testing.T) { 110 | s := newTestBenchRandomScalar(t) 111 | 112 | var pEdwards EdwardsPoint 113 | pEdwards.MulBasepoint(ED25519_BASEPOINT_TABLE, s) 114 | 115 | var pMontgomery MontgomeryPoint 116 | pMontgomery.SetEdwards(&pEdwards) 117 | 118 | var expected EdwardsPoint 119 | expected.Mul(&pEdwards, s) 120 | 121 | var result MontgomeryPoint 122 | result.Mul(&pMontgomery, s) 123 | 124 | var expectedMontgomery MontgomeryPoint 125 | expectedMontgomery.SetEdwards(&expected) 126 | if result.Equal(&expectedMontgomery) != 1 { 127 | t.Fatalf("s * p_edwards != s * p_montgomery (Got: %v, %v)", expectedMontgomery, result) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /curve/ristretto_precomputation.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package curve 31 | 32 | import "github.com/oasisprotocol/curve25519-voi/curve/scalar" 33 | 34 | // ExpandedRistreetoPoint is a RistrettoPoint stored in an expanded 35 | // representation for the purpose of accelerating scalar point 36 | // multiply operations. 37 | // 38 | // The default value is NOT valid and MUST only be used as a receiver. 39 | type ExpandedRistrettoPoint struct { 40 | inner ExpandedEdwardsPoint 41 | } 42 | 43 | // Point returns the Ristretto point represented by the expanded point. 44 | func (ep *ExpandedRistrettoPoint) Point() *RistrettoPoint { 45 | var p RistrettoPoint 46 | p.inner.Set(&ep.inner.point) 47 | return &p 48 | } 49 | 50 | // SetExpandedRistrettoPoint sets the expanded point to the Ristretto point. 51 | func (ep *ExpandedRistrettoPoint) SetRistrettoPoint(p *RistrettoPoint) *ExpandedRistrettoPoint { 52 | ep.inner.SetEdwardsPoint(&p.inner) 53 | return ep 54 | } 55 | 56 | // NewExpandedRistrettoPoint creates an expanded representation of a 57 | // Ristretto point. 58 | func NewExpandedRistrettoPoint(p *RistrettoPoint) *ExpandedRistrettoPoint { 59 | var ep ExpandedRistrettoPoint 60 | return ep.SetRistrettoPoint(p) 61 | } 62 | 63 | // ExpandedDoubleScalarMulBasepointVartime sets `p = (aA + bB)` in variable-time, 64 | // where B is the Ed25519 basepoint, and returns p. 65 | func (p *RistrettoPoint) ExpandedDoubleScalarMulBasepointVartime(a *scalar.Scalar, A *ExpandedRistrettoPoint, b *scalar.Scalar) *RistrettoPoint { 66 | p.inner.ExpandedDoubleScalarMulBasepointVartime(a, &A.inner, b) 67 | return p 68 | } 69 | 70 | // ExpandedTripleScalarMulBasepoint sets `p = [delta a]A + [delta b]B - [delta]C` 71 | // in variable-time, where delta is a value invertible mod ell, which 72 | // is selected internally to this method. 73 | func (p *RistrettoPoint) ExpandedTripleScalarMulBasepointVartime(a *scalar.Scalar, A *ExpandedRistrettoPoint, b *scalar.Scalar, C *RistrettoPoint) *RistrettoPoint { 74 | p.inner.ExpandedTripleScalarMulBasepointVartime(a, &A.inner, b, &C.inner) 75 | return p 76 | } 77 | 78 | // ExpandedMultiscalarMulVartime sets `p = staticScalars[0] * staticPoints[0] + 79 | // ... + staticScalars[n] * staticPoints[n] + dynamicScalars[0] * 80 | // dynamicPoints[0] + ... + dynamicScalars[n] * dynamicPoints[n]` in variable-time, 81 | // and returns p. 82 | // 83 | // WARNING: This function will panic if `len(staticScalars) != len(staticPoints)` 84 | // or `len(dynamicScalars) != len(dynamicPoints)`. 85 | func (p *RistrettoPoint) ExpandedMultiscalarMulVartime(staticScalars []*scalar.Scalar, staticPoints []*ExpandedRistrettoPoint, dynamicScalars []*scalar.Scalar, dynamicPoints []*RistrettoPoint) *RistrettoPoint { 86 | staticRistrettoPoints := make([]*ExpandedEdwardsPoint, 0, len(staticPoints)) 87 | for _, point := range staticPoints { 88 | staticRistrettoPoints = append(staticRistrettoPoints, &point.inner) 89 | } 90 | dynamicRistrettoPoints := make([]*EdwardsPoint, 0, len(dynamicPoints)) 91 | for _, point := range dynamicPoints { 92 | dynamicRistrettoPoints = append(dynamicRistrettoPoints, &point.inner) 93 | } 94 | 95 | p.inner.ExpandedMultiscalarMulVartime(staticScalars, staticRistrettoPoints, dynamicScalars, dynamicRistrettoPoints) 96 | return p 97 | } 98 | -------------------------------------------------------------------------------- /curve/scalar/constants_u32.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | //go:build (386 || arm || mips || mipsle || wasm || mips64le || mips64 || riscv64 || loong64 || force32bit) && !force64bit 33 | 34 | package scalar 35 | 36 | // `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493. 37 | var constL unpackedScalar = unpackedScalar{ 38 | 0x1cf5d3ed, 0x009318d2, 0x1de73596, 0x1df3bd45, 39 | 0x0000014d, 0x00000000, 0x00000000, 0x00000000, 40 | 0x00100000, 41 | } 42 | 43 | // `R` = R % L where R = 2^261. 44 | var constR unpackedScalar = unpackedScalar{ 45 | 0x114df9ed, 0x1a617303, 0x0f7c098c, 0x16793167, 46 | 0x1ffd656e, 0x1fffffff, 0x1fffffff, 0x1fffffff, 47 | 0x000fffff, 48 | } 49 | 50 | // `RR` = (R^2) % L where R = 2^261. 51 | var constRR = unpackedScalar{ 52 | 0x0b5f9d12, 0x1e141b17, 0x158d7f3d, 0x143f3757, 53 | 0x1972d781, 0x042feb7c, 0x1ceec73d, 0x1e184d1e, 54 | 0x0005046d, 55 | } 56 | 57 | // `L` * `LFACTOR` = -1 (mod 2^29) 58 | const constLFACTOR uint32 = 0x12547e1b 59 | -------------------------------------------------------------------------------- /curve/scalar/constants_u64.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | //go:build (amd64 || arm64 || ppc64le || ppc64 || s390x || force64bit) && !force32bit 33 | 34 | package scalar 35 | 36 | // `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493. 37 | var constL unpackedScalar = unpackedScalar{ 38 | 0x0002631a5cf5d3ed, 39 | 0x000dea2f79cd6581, 40 | 0x000000000014def9, 41 | 0x0000000000000000, 42 | 0x0000100000000000, 43 | } 44 | 45 | // `R` = R % L where R = 2^260. 46 | var constR unpackedScalar = unpackedScalar{ 47 | 0x000f48bd6721e6ed, 48 | 0x0003bab5ac67e45a, 49 | 0x000fffffeb35e51b, 50 | 0x000fffffffffffff, 51 | 0x00000fffffffffff, 52 | } 53 | 54 | // `RR` = (R^2) % L where R = 2^260. 55 | var constRR = unpackedScalar{ 56 | 0x0009d265e952d13b, 57 | 0x000d63c715bea69f, 58 | 0x0005be65cb687604, 59 | 0x0003dceec73d217f, 60 | 0x000009411b7c309a, 61 | } 62 | 63 | // `L` * `LFACTOR` = -1 (mod 2^52). 64 | const constLFACTOR uint64 = 0x51da312547e1b 65 | -------------------------------------------------------------------------------- /curve/scalar/sc_minimal.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 The Go Authors. All rights reserved. 2 | // Copyright (c) 2019-2021 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package scalar 31 | 32 | import "encoding/binary" 33 | 34 | // order is the order of Curve25519 in little-endian form. 35 | var order = func() [4]uint64 { 36 | var orderBytes [ScalarSize]byte 37 | _ = BASEPOINT_ORDER.ToBytes(orderBytes[:]) 38 | 39 | var ret [4]uint64 40 | for i := range ret { 41 | ret[i] = binary.LittleEndian.Uint64(orderBytes[i*8 : (i+1)*8]) 42 | } 43 | 44 | return ret 45 | }() 46 | 47 | // ScMinimalVartime returns true if the given byte-encoded scalar is 48 | // less than the order of the curve, in variable-time. 49 | // 50 | // This method is intended for verification applications, and is 51 | // significantly faster than deserializing the scalar and calling 52 | // IsCanonical. 53 | func ScMinimalVartime(scalar []byte) bool { 54 | if scalar[31]&240 == 0 { 55 | // 4 most significant bits unset, succeed fast 56 | return true 57 | } 58 | if scalar[31]&224 != 0 { 59 | // Any of the 3 most significant bits set, fail fast 60 | return false 61 | } 62 | 63 | // 4th most significant bit set (unlikely), actually check vs order 64 | for i := 3; ; i-- { 65 | v := binary.LittleEndian.Uint64(scalar[i*8:]) 66 | if v > order[i] { 67 | return false 68 | } else if v < order[i] { 69 | break 70 | } else if i == 0 { 71 | return false 72 | } 73 | } 74 | 75 | return true 76 | } 77 | -------------------------------------------------------------------------------- /curve/scalar/scalar_u32_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | //go:build (386 || arm || mips || mipsle || wasm || mips64le || mips64 || riscv64 || loong64 || force32bit) && !force64bit 33 | 34 | package scalar 35 | 36 | // Having a way to declare file scoped globals will be really nice, 37 | // since the packed tests also use some of these variable names. 38 | var unpackedTestConstants = map[string]*unpackedScalar{ 39 | // Note: x is 2^253-1 which is slightly larger than the largest scalar produced by 40 | // this implementation (l-1), and should verify there are no overflows for valid scalars 41 | // 42 | // x = 2^253-1 = 14474011154664524427946373126085988481658748083205070504932198000989141204991 43 | // x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l 44 | // x = 5147078182513738803124273553712992179887200054963030844803268920753008712037*R mod l in Montgomery form 45 | "X": { 46 | 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 47 | 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 48 | 0x001fffff, 49 | }, 50 | 51 | // x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l 52 | "XX": { 53 | 0x00217559, 0x000b3401, 0x103ff43b, 0x1462a62c, 54 | 0x1d6f9f38, 0x18e7a42f, 0x09a3dcee, 0x008dbe18, 55 | 0x0006ce65, 56 | }, 57 | 58 | // x^2 = 2912514428060642753613814151688322857484807845836623976981729207238463947987*R mod l in Montgomery form 59 | "XX_MONT": { 60 | 0x152b4d2e, 0x0571d53b, 0x1da6d964, 0x188663b6, 61 | 0x1d1b5f92, 0x19d50e3f, 0x12306c29, 0x0c6f26fe, 62 | 0x00030edb, 63 | }, 64 | 65 | // y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 66 | "Y": { 67 | 0x1e1458fa, 0x165ba838, 0x1d787b36, 0x0e577f3a, 68 | 0x1d2baf06, 0x1d689a19, 0x1fff3047, 0x117704ab, 69 | 0x000d9601, 70 | }, 71 | 72 | // x*y = 36752150652102274958925982391442301741 73 | "XY": { 74 | 0x0ba7632d, 0x017736bb, 0x15c76138, 0x0c69daa1, 75 | 0x000001ba, 0x00000000, 0x00000000, 0x00000000, 76 | 0x00000000, 77 | }, 78 | 79 | // x*y = 3783114862749659543382438697751927473898937741870308063443170013240655651591*R mod l in Montgomery form 80 | "XY_MONT": { 81 | 0x077b51e1, 0x1c64e119, 0x02a19ef5, 0x18d2129e, 82 | 0x00de0430, 0x045a7bc8, 0x04cfc7c9, 0x1c002681, 83 | 0x000bdc1c, 84 | }, 85 | 86 | // a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 87 | "A": { 88 | 0x07b3be89, 0x02291b60, 0x14a99f03, 0x07dc3787, 89 | 0x0a782aae, 0x16262525, 0x0cfdb93f, 0x13f5718d, 90 | 0x000532da, 91 | }, 92 | 93 | // b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 94 | "B": { 95 | 0x15421564, 0x1e69fd72, 0x093d9692, 0x161785be, 96 | 0x1587d69f, 0x09d9dada, 0x130246c0, 0x0c0a8e72, 97 | 0x000acd25, 98 | }, 99 | 100 | // a+b = 0 101 | // a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 102 | "AB": { 103 | 0x0f677d12, 0x045236c0, 0x09533e06, 0x0fb86f0f, 104 | 0x14f0555c, 0x0c4c4a4a, 0x19fb727f, 0x07eae31a, 105 | 0x000a65b5, 106 | }, 107 | 108 | // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 109 | "C": { 110 | 0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, 111 | 0x1be65d00, 0x19e90bfa, 0x08f73bb1, 0x036f8613, 112 | 0x00039941, 113 | }, 114 | } 115 | -------------------------------------------------------------------------------- /curve/scalar/scalar_u64_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | //go:build (amd64 || arm64 || ppc64le || ppc64 || s390x || force64bit) && !force32bit 33 | 34 | package scalar 35 | 36 | // Having a way to declare file scoped globals will be really nice, 37 | // since the packed tests also use some of these variable names. 38 | var unpackedTestConstants = map[string]*unpackedScalar{ 39 | // Note: x is 2^253-1 which is slightly larger than the largest scalar produced by 40 | // this implementation (l-1), and should verify there are no overflows for valid scalars 41 | // 42 | // x = 2^253-1 = 14474011154664524427946373126085988481658748083205070504932198000989141204991 43 | // x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l 44 | // x = 5147078182513738803124273553712992179887200054963030844803268920753008712037*R mod l in Montgomery form 45 | "X": { 46 | 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 47 | 0x00001fffffffffff, 48 | }, 49 | 50 | // x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l 51 | "XX": { 52 | 0x0001668020217559, 0x000531640ffd0ec0, 0x00085fd6f9f38a31, 0x000c268f73bb1cf4, 53 | 0x000006ce65046df0, 54 | }, 55 | 56 | // x^2 = 2912514428060642753613814151688322857484807845836623976981729207238463947987*R mod l in Montgomery form 57 | "XX_MONT": { 58 | 0x000c754eea569a5c, 0x00063b6ed36cb215, 0x0008ffa36bf25886, 0x000e9183614e7543, 59 | 0x0000061db6c6f26f, 60 | }, 61 | 62 | // y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 63 | "Y": { 64 | 0x000b75071e1458fa, 0x000bf9d75e1ecdac, 0x000433d2baf0672b, 0x0005fffcc11fad13, 65 | 0x00000d96018bb825, 66 | }, 67 | 68 | // x*y = 36752150652102274958925982391442301741 69 | "XY": { 70 | 0x000ee6d76ba7632d, 0x000ed50d71d84e02, 0x00000000001ba634, 0x0000000000000000, 71 | 0x0000000000000000, 72 | }, 73 | 74 | // x*y = 3783114862749659543382438697751927473898937741870308063443170013240655651591*R mod l in Montgomery form 75 | "XY_MONT": { 76 | 0x0006d52bf200cfd5, 0x00033fb1d7021570, 0x000f201bc07139d8, 0x0001267e3e49169e, 77 | 0x000007b839c00268, 78 | }, 79 | 80 | // a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 81 | "A": { 82 | 0x0005236c07b3be89, 0x0001bc3d2a67c0c4, 0x000a4aa782aae3ee, 0x0006b3f6e4fec4c4, 83 | 0x00000532da9fab8c, 84 | }, 85 | 86 | // b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 87 | "B": { 88 | 0x000d3fae55421564, 0x000c2df24f65a4bc, 0x0005b5587d69fb0b, 0x00094c091b013b3b, 89 | 0x00000acd25605473, 90 | }, 91 | 92 | // a+b = 0 93 | // a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 94 | "AB": { 95 | 0x000a46d80f677d12, 0x0003787a54cf8188, 0x0004954f0555c7dc, 0x000d67edc9fd8989, 96 | 0x00000a65b53f5718, 97 | }, 98 | 99 | // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 100 | "C": { 101 | 0x000611e3449c0f00, 0x000a768859347a40, 0x0007f5be65d00e1b, 0x0009a3dceec73d21, 102 | 0x00000399411b7c30, 103 | }, 104 | } 105 | -------------------------------------------------------------------------------- /curve/scalar_mul_abglsv_pornin_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Jack Grigg. All rights reserved. 2 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | package curve 32 | 33 | import ( 34 | "crypto/rand" 35 | "testing" 36 | 37 | "github.com/oasisprotocol/curve25519-voi/curve/scalar" 38 | ) 39 | 40 | func testEdwardsMulAbglsvPorninVartime(t *testing.T) { 41 | // Returns what C should be to satisfy the equation. 42 | deriveC := func(out *EdwardsPoint, a *scalar.Scalar, A *EdwardsPoint, b *scalar.Scalar) { 43 | var aA EdwardsPoint 44 | aA.Mul(A, a) 45 | 46 | var bB EdwardsPoint 47 | bB.Mul(ED25519_BASEPOINT_POINT, b) 48 | 49 | out.Add(&aA, &bB) 50 | } 51 | 52 | // Returns the results of the equation, calculated the hard way. 53 | slowMul := func(a *scalar.Scalar, A *EdwardsPoint, b *scalar.Scalar, C *EdwardsPoint) *EdwardsPoint { 54 | var aA_plus_bB EdwardsPoint 55 | deriveC(&aA_plus_bB, a, A, b) 56 | 57 | var ret EdwardsPoint 58 | ret.Sub(&aA_plus_bB, C) 59 | 60 | return &ret 61 | } 62 | 63 | var ( 64 | a, b scalar.Scalar 65 | A, C EdwardsPoint 66 | 67 | actual EdwardsPoint 68 | ) 69 | 70 | // The equation evaluates to the identity, so will be unaffected by delta. 71 | a.SetUint64(2) 72 | A.double(ED25519_BASEPOINT_POINT) 73 | b.SetUint64(4) 74 | C.double(C.double(&A)) 75 | 76 | edwardsMulAbglsvPorninVartime(&actual, &a, &A, &b, &C) 77 | expected := slowMul(&a, &A, &b, &C) 78 | if !expected.IsIdentity() { 79 | t.Fatalf("slowMul(2, B, 4, 8B) != identity (Got: %v)", expected) 80 | } 81 | if expected.Equal(&actual) != 1 || !actual.IsIdentity() { 82 | t.Fatalf("mul(2, B, 4, 8B) != identity (Got: %v)", actual) 83 | } 84 | 85 | expandedA := NewExpandedEdwardsPoint(&A) 86 | expandedEdwardsMulAbglsvPorninVartime(&actual, &a, expandedA, &b, &C) 87 | if expected.Equal(&actual) != 1 || !actual.IsIdentity() { 88 | t.Fatalf("expandedMul(2, B , 4, 4, 8B) != identity (Got: %v)", actual) 89 | } 90 | 91 | for i := 0; i < 100; i++ { 92 | if _, err := a.SetRandom(rand.Reader); err != nil { 93 | t.Fatalf("a.SetRandom(): %v", err) 94 | } 95 | A.Mul(ED25519_BASEPOINT_POINT, newTestBenchRandomScalar(t)) 96 | if _, err := b.SetRandom(rand.Reader); err != nil { 97 | t.Fatalf("b.SetRandom(): %v", err) 98 | } 99 | 100 | // With a correctly-constructed C, we get the identity. 101 | deriveC(&C, &a, &A, &b) 102 | expected = slowMul(&a, &A, &b, &C) 103 | if !expected.IsIdentity() { 104 | t.Fatalf("slowMul(a, A, b, C) != identity (Got: %v)", expected) 105 | } 106 | edwardsMulAbglsvPorninVartime(&actual, &a, &A, &b, &C) 107 | if expected.Equal(&actual) != 1 || !actual.IsIdentity() { 108 | t.Fatalf("mul(a, A, b, C) != identity (Got: %v)", actual) 109 | } 110 | 111 | expandedA = NewExpandedEdwardsPoint(&A) 112 | expandedEdwardsMulAbglsvPorninVartime(&actual, &a, expandedA, &b, &C) 113 | if expected.Equal(&actual) != 1 || !actual.IsIdentity() { 114 | t.Fatalf("expandedMul(a, A, b, C) != identity (Got: %v)", actual) 115 | } 116 | 117 | // With a random C, with high probability we do not get the identity. 118 | for { 119 | // Loop till we get a C that is sufficiently random. 120 | C.Mul(ED25519_BASEPOINT_POINT, newTestBenchRandomScalar(t)) 121 | expected = slowMul(&a, &A, &b, &C) 122 | if !expected.IsIdentity() { 123 | break 124 | } 125 | } 126 | edwardsMulAbglsvPorninVartime(&actual, &a, &A, &b, &C) 127 | if actual.IsIdentity() { 128 | t.Fatalf("mul(a, A, b, random C) = identity") 129 | } 130 | expandedEdwardsMulAbglsvPorninVartime(&actual, &a, expandedA, &b, &C) 131 | if actual.IsIdentity() { 132 | t.Fatalf("expandedMul(a, A, b, random C) = identity") 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /curve/scalar_mul_basepoint.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package curve 33 | 34 | import "github.com/oasisprotocol/curve25519-voi/curve/scalar" 35 | 36 | func newEdwardsBasepointTable(basepoint *EdwardsPoint) *EdwardsBasepointTable { 37 | switch supportsVectorizedEdwards { 38 | case true: 39 | return &EdwardsBasepointTable{ 40 | innerVector: newEdwardsBasepointTableVector(basepoint), 41 | } 42 | default: 43 | return &EdwardsBasepointTable{ 44 | inner: newEdwardsBasepointTableGeneric(basepoint), 45 | } 46 | } 47 | } 48 | 49 | func edwardsBasepointTableInner(tbl *EdwardsBasepointTable) *EdwardsPoint { 50 | switch supportsVectorizedEdwards { 51 | case true: 52 | return tbl.innerVector.Basepoint() 53 | default: 54 | return tbl.inner.Basepoint() 55 | } 56 | } 57 | 58 | func edwardsBasepointTableMul(out *EdwardsPoint, tbl *EdwardsBasepointTable, scalar *scalar.Scalar) *EdwardsPoint { 59 | switch supportsVectorizedEdwards { 60 | case true: 61 | return tbl.innerVector.Mul(out, scalar) 62 | default: 63 | return tbl.inner.Mul(out, scalar) 64 | } 65 | } 66 | 67 | // edwardsBasepointTableGeneric is a portable precomputed basepoint multiply. 68 | type edwardsBasepointTableGeneric [32]affineNielsPointLookupTable 69 | 70 | func (tbl *edwardsBasepointTableGeneric) Basepoint() *EdwardsPoint { 71 | // tbl[0].lookup(1) = 1*(16^2)^0*B 72 | // but as an `affineNielsPoint`, so convert to extended. 73 | return tbl[0].Basepoint() 74 | } 75 | 76 | func (tbl *edwardsBasepointTableGeneric) Mul(out *EdwardsPoint, scalar *scalar.Scalar) *EdwardsPoint { 77 | a := scalar.ToRadix16() 78 | 79 | out.Identity() 80 | 81 | var sum completedPoint 82 | for i := 1; i < 64; i = i + 2 { 83 | aPt := tbl[i/2].Lookup(a[i]) 84 | out.setCompleted(sum.AddEdwardsAffineNiels(out, &aPt)) 85 | } 86 | 87 | out.mulByPow2(out, 4) 88 | 89 | for i := 0; i < 64; i = i + 2 { 90 | aPt := tbl[i/2].Lookup(a[i]) 91 | out.setCompleted(sum.AddEdwardsAffineNiels(out, &aPt)) 92 | } 93 | 94 | return out 95 | } 96 | 97 | func newEdwardsBasepointTableGeneric(basepoint *EdwardsPoint) *edwardsBasepointTableGeneric { 98 | var ( 99 | table edwardsBasepointTableGeneric 100 | p EdwardsPoint 101 | ) 102 | 103 | p.Set(basepoint) 104 | for i := 0; i < 32; i++ { 105 | table[i] = newAffineNielsPointLookupTable(&p) 106 | p.mulByPow2(&p, 8) 107 | } 108 | 109 | return &table 110 | } 111 | 112 | // edwardsBasepointTableVector is a vectorized precomputed basepoint multiply. 113 | type edwardsBasepointTableVector [32]cachedPointLookupTable 114 | 115 | func (tbl *edwardsBasepointTableVector) Basepoint() *EdwardsPoint { 116 | // tbl[0].lookup(1) = 1*(16^2)^0*B 117 | // but as an `cachedPoint`, so convert to extended. 118 | return tbl[0].Basepoint() 119 | } 120 | 121 | func (tbl *edwardsBasepointTableVector) Mul(out *EdwardsPoint, scalar *scalar.Scalar) *EdwardsPoint { 122 | a := scalar.ToRadix16() 123 | 124 | var p extendedPoint 125 | p.Identity() 126 | 127 | for i := 1; i < 64; i = i + 2 { 128 | cPt := tbl[i/2].Lookup(a[i]) 129 | p.AddExtendedCached(&p, &cPt) 130 | } 131 | 132 | p.MulByPow2(&p, 4) 133 | 134 | for i := 0; i < 64; i = i + 2 { 135 | cPt := tbl[i/2].Lookup(a[i]) 136 | p.AddExtendedCached(&p, &cPt) 137 | } 138 | 139 | out.setExtended(&p) 140 | 141 | return out 142 | } 143 | 144 | func newEdwardsBasepointTableVector(basepoint *EdwardsPoint) *edwardsBasepointTableVector { 145 | var ( 146 | table edwardsBasepointTableVector 147 | p EdwardsPoint 148 | ) 149 | 150 | p.Set(basepoint) 151 | for i := 0; i < 32; i++ { 152 | table[i] = newCachedPointLookupTable(&p) 153 | p.mulByPow2(&p, 8) 154 | } 155 | 156 | return &table 157 | } 158 | -------------------------------------------------------------------------------- /curve/scalar_mul_pippenger_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Oglev Andreev. All rights reserved. 2 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | package curve 32 | 33 | import ( 34 | "testing" 35 | 36 | "github.com/oasisprotocol/curve25519-voi/curve/scalar" 37 | ) 38 | 39 | func testEdwardsMultiscalarMulPippengerVartime(t *testing.T) { 40 | n := 512 41 | x := scalar.New().Invert(scalar.NewFromUint64(2128506)) 42 | y := scalar.New().Invert(scalar.NewFromUint64(4443282)) 43 | 44 | points := make([]*EdwardsPoint, 0, n) 45 | for i := 0; i < n; i++ { 46 | tmp := scalar.NewFromUint64(1 + uint64(i)) 47 | 48 | var point EdwardsPoint 49 | point.Mul(ED25519_BASEPOINT_POINT, tmp) 50 | points = append(points, &point) 51 | } 52 | 53 | scalars := make([]*scalar.Scalar, 0, n) 54 | for i := 0; i < n; i++ { 55 | tmp := scalar.New().Mul(scalar.NewFromUint64(uint64(i)), y) 56 | tmp.Add(x, tmp) 57 | scalars = append(scalars, tmp) 58 | } 59 | 60 | premultiplied := make([]*EdwardsPoint, 0, n) 61 | for i := 0; i < n; i++ { 62 | var point EdwardsPoint 63 | point.Mul(points[i], scalars[i]) 64 | premultiplied = append(premultiplied, &point) 65 | } 66 | 67 | for n > 0 { 68 | var control EdwardsPoint 69 | control.Sum(premultiplied[:n]) 70 | 71 | var subject EdwardsPoint 72 | edwardsMultiscalarMulPippengerVartime(&subject, scalars[:n], points[:n]) 73 | 74 | if subject.Equal(&control) == 0 { 75 | t.Fatalf("multiscalarMulPippengerVartime(scalars[:%d], points[:%d] != control (Got: %v)", n, n, subject) 76 | } 77 | 78 | n = n / 2 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /curve/scalar_mul_variable_base.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package curve 33 | 34 | import "github.com/oasisprotocol/curve25519-voi/curve/scalar" 35 | 36 | func edwardsMul(out, point *EdwardsPoint, scalar *scalar.Scalar) *EdwardsPoint { 37 | switch supportsVectorizedEdwards { 38 | case true: 39 | return edwardsMulVector(out, point, scalar) 40 | default: 41 | return edwardsMulGeneric(out, point, scalar) 42 | } 43 | } 44 | 45 | func edwardsMulGeneric(out, point *EdwardsPoint, scalar *scalar.Scalar) *EdwardsPoint { 46 | // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] 47 | lookupTable := newProjectiveNielsPointLookupTable(point) 48 | // Setting s = scalar, compute 49 | // 50 | // s = s_0 + s_1*16^1 + ... + s_63*16^63, 51 | // 52 | // with `-8 <= s_i < 8` for `0 <= i < 63` and `-8 <= s_63 <= 8`. 53 | scalarDigits := scalar.ToRadix16() 54 | // Compute s*P as 55 | // 56 | // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) 57 | // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 58 | // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) 59 | // 60 | // We sum right-to-left. 61 | 62 | // Unwrap first loop iteration to save computing 16*identity 63 | var ( 64 | tmp3 EdwardsPoint 65 | tmp2 projectivePoint 66 | tmp1 completedPoint 67 | ) 68 | tmp3.Identity() 69 | tmp := lookupTable.Lookup(scalarDigits[63]) 70 | tmp1.AddEdwardsProjectiveNiels(&tmp3, &tmp) 71 | // Now tmp1 = s_63*P in P1xP1 coords 72 | for i := 62; i >= 0; i-- { 73 | tmp2.SetCompleted(&tmp1) // tmp2 = (prev) in P2 coords 74 | tmp1.Double(&tmp2) // tmp1 = 2*(prev) in P1xP1 coords 75 | tmp2.SetCompleted(&tmp1) // tmp2 = 2*(prev) in P2 coords 76 | tmp1.Double(&tmp2) // tmp1 = 4*(prev) in P1xP1 coords 77 | tmp2.SetCompleted(&tmp1) // tmp2 = 4*(prev) in P2 coords 78 | tmp1.Double(&tmp2) // tmp1 = 8*(prev) in P1xP1 coords 79 | tmp2.SetCompleted(&tmp1) // tmp2 = 8*(prev) in P2 coords 80 | tmp1.Double(&tmp2) // tmp1 = 16*(prev) in P1xP1 coords 81 | tmp3.setCompleted(&tmp1) // tmp3 = 16*(prev) in P3 coords 82 | tmp = lookupTable.Lookup(scalarDigits[i]) 83 | tmp1.AddEdwardsProjectiveNiels(&tmp3, &tmp) 84 | // Now tmp1 = s_i*P + 16*(prev) in P1xP1 coords 85 | } 86 | return out.setCompleted(&tmp1) 87 | } 88 | 89 | func edwardsMulVector(out, point *EdwardsPoint, scalar *scalar.Scalar) *EdwardsPoint { 90 | lookupTable := newCachedPointLookupTable(point) 91 | 92 | scalarDigits := scalar.ToRadix16() 93 | var ( 94 | q extendedPoint 95 | tmp cachedPoint 96 | ) 97 | q.Identity() 98 | for i := 63; i >= 0; i-- { 99 | q.MulByPow2(&q, 4) 100 | tmp = lookupTable.Lookup(scalarDigits[i]) 101 | q.AddExtendedCached(&q, &tmp) 102 | } 103 | return out.setExtended(&q) 104 | } 105 | -------------------------------------------------------------------------------- /curve/scalar_mul_vartime_double_base.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package curve 33 | 34 | import "github.com/oasisprotocol/curve25519-voi/curve/scalar" 35 | 36 | func edwardsDoubleScalarMulBasepointVartime(out *EdwardsPoint, a *scalar.Scalar, A *EdwardsPoint, b *scalar.Scalar) *EdwardsPoint { 37 | switch supportsVectorizedEdwards { 38 | case true: 39 | return edwardsDoubleScalarMulBasepointVartimeVector(out, a, A, b) 40 | default: 41 | return edwardsDoubleScalarMulBasepointVartimeGeneric(out, a, A, b) 42 | } 43 | } 44 | 45 | func expandedEdwardsDoubleScalarMulBasepointVartime(out *EdwardsPoint, a *scalar.Scalar, A *ExpandedEdwardsPoint, b *scalar.Scalar) *EdwardsPoint { 46 | switch supportsVectorizedEdwards { 47 | case true: 48 | return edwardsDoubleScalarMulBasepointVartimeVectorInner(out, a, A.innerVector, b) 49 | default: 50 | return edwardsDoubleScalarMulBasepointVartimeGenericInner(out, a, A.inner, b) 51 | } 52 | } 53 | 54 | func edwardsDoubleScalarMulBasepointVartimeGeneric(out *EdwardsPoint, a *scalar.Scalar, A *EdwardsPoint, b *scalar.Scalar) *EdwardsPoint { 55 | tableA := newProjectiveNielsPointNafLookupTable(A) 56 | 57 | return edwardsDoubleScalarMulBasepointVartimeGenericInner(out, a, &tableA, b) 58 | } 59 | 60 | func edwardsDoubleScalarMulBasepointVartimeGenericInner(out *EdwardsPoint, a *scalar.Scalar, tableA *projectiveNielsPointNafLookupTable, b *scalar.Scalar) *EdwardsPoint { 61 | aNaf := a.NonAdjacentForm(5) 62 | bNaf := b.NonAdjacentForm(8) 63 | 64 | // Find the starting index. 65 | var i int 66 | for j := 255; j >= 0; j-- { 67 | if aNaf[j] != 0 || bNaf[j] != 0 { 68 | i = j 69 | break 70 | } 71 | } 72 | 73 | tableB := &constAFFINE_ODD_MULTIPLES_OF_BASEPOINT 74 | 75 | var r projectivePoint 76 | r.Identity() 77 | 78 | var ( 79 | tEp EdwardsPoint 80 | t completedPoint 81 | ) 82 | for { 83 | t.Double(&r) 84 | 85 | if aNaf[i] > 0 { 86 | t.AddEdwardsProjectiveNiels(tEp.setCompleted(&t), tableA.Lookup(uint8(aNaf[i]))) 87 | } else if aNaf[i] < 0 { 88 | t.SubEdwardsProjectiveNiels(tEp.setCompleted(&t), tableA.Lookup(uint8(-aNaf[i]))) 89 | } 90 | 91 | if bNaf[i] > 0 { 92 | t.AddEdwardsAffineNiels(tEp.setCompleted(&t), tableB.Lookup(uint8(bNaf[i]))) 93 | } else if bNaf[i] < 0 { 94 | t.SubEdwardsAffineNiels(tEp.setCompleted(&t), tableB.Lookup(uint8(-bNaf[i]))) 95 | } 96 | 97 | r.SetCompleted(&t) 98 | 99 | if i == 0 { 100 | break 101 | } 102 | i-- 103 | } 104 | 105 | return out.setProjective(&r) 106 | } 107 | 108 | func edwardsDoubleScalarMulBasepointVartimeVector(out *EdwardsPoint, a *scalar.Scalar, A *EdwardsPoint, b *scalar.Scalar) *EdwardsPoint { 109 | tableA := newCachedPointNafLookupTable(A) 110 | 111 | return edwardsDoubleScalarMulBasepointVartimeVectorInner(out, a, &tableA, b) 112 | } 113 | 114 | func edwardsDoubleScalarMulBasepointVartimeVectorInner(out *EdwardsPoint, a *scalar.Scalar, tableA *cachedPointNafLookupTable, b *scalar.Scalar) *EdwardsPoint { 115 | aNaf := a.NonAdjacentForm(5) 116 | bNaf := b.NonAdjacentForm(8) 117 | 118 | var i int 119 | for j := 255; j >= 0; j-- { 120 | if aNaf[j] != 0 || bNaf[j] != 0 { 121 | i = j 122 | break 123 | } 124 | } 125 | 126 | tableB := constVECTOR_ODD_MULTIPLES_OF_BASEPOINT 127 | 128 | var q extendedPoint 129 | q.Identity() 130 | 131 | for { 132 | q.Double(&q) 133 | 134 | if aNaf[i] > 0 { 135 | q.AddExtendedCached(&q, tableA.Lookup(uint8(aNaf[i]))) 136 | } else if aNaf[i] < 0 { 137 | q.SubExtendedCached(&q, tableA.Lookup(uint8(-aNaf[i]))) 138 | } 139 | 140 | if bNaf[i] > 0 { 141 | q.AddExtendedCached(&q, tableB.Lookup(uint8(bNaf[i]))) 142 | } else if bNaf[i] < 0 { 143 | q.SubExtendedCached(&q, tableB.Lookup(uint8(-bNaf[i]))) 144 | } 145 | 146 | if i == 0 { 147 | break 148 | } 149 | i-- 150 | } 151 | 152 | return out.setExtended(&q) 153 | } 154 | -------------------------------------------------------------------------------- /curve/window_amd64.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build amd64 && !purego && !force32bit 31 | 32 | package curve 33 | 34 | //go:noescape 35 | func lookupAffineNiels(table *affineNielsPointLookupTable, out *affineNielsPoint, xabs uint8) 36 | 37 | //go:noescape 38 | func lookupCached(table *cachedPointLookupTable, out *cachedPoint, xabs uint8) 39 | -------------------------------------------------------------------------------- /curve/window_amd64.s: -------------------------------------------------------------------------------- 1 | // Code generated by command: go run window.go. DO NOT EDIT. 2 | 3 | //go:build amd64 && !purego && !force32bit 4 | 5 | #include "textflag.h" 6 | 7 | // func lookupAffineNiels(table *affineNielsPointLookupTable, out *affineNielsPoint, xabs uint8) 8 | // Requires: SSE2 9 | TEXT ·lookupAffineNiels(SB), NOSPLIT|NOFRAME, $0-17 10 | // This is moderately annoying due to having 3x5 64-bit elements, 11 | // which does not nicely fit into vector registers. This is 12 | // handled by duplicating one element in 2 registers, since 13 | // doing so keeps the rest of the code straight forward. 14 | // 15 | // v0 = y_plus_x[0], y_plus_x[1] 16 | // v1 = y_plus_x[2], y_plus_x[3] 17 | // v2 = y_plus_x[4], y_minus_x[0] 18 | // v3 = y_minus_x[1], y_minus_x[2] 19 | // v4 = y_minus_x[3], y_minus_x[4] 20 | // v5 = xy2d[0], xy2d[1] 21 | // v6 = xy2d[1] (*), xy2d[2] 22 | // v7 = xy2d[3], xy2d[4] 23 | // 24 | // Note: Before I get tempted to rewrite this to use AVX2 again 25 | // I will to take a moment to remind myself that the AVX2 backend 26 | // does not use this table. 27 | 28 | MOVQ table+0(FP), AX 29 | 30 | // Build the mask, zero all the registers 31 | MOVBQZX xabs+16(FP), CX 32 | MOVD CX, X0 33 | PSHUFD $0x00, X0, X0 34 | PXOR X2, X2 35 | PXOR X3, X3 36 | PXOR X4, X4 37 | PXOR X5, X5 38 | PXOR X6, X6 39 | PXOR X7, X7 40 | PXOR X8, X8 41 | PXOR X9, X9 42 | 43 | // 0: Identity element (1, 1, 0) 44 | PXOR X1, X1 45 | PCMPEQL X0, X1 46 | MOVQ $0x0000000000000001, CX 47 | MOVQ CX, X10 48 | PXOR X11, X11 49 | PUNPCKLQDQ X10, X11 50 | PAND X1, X10 51 | PAND X1, X11 52 | POR X10, X2 53 | POR X11, X4 54 | 55 | // 1 .. 8 56 | MOVQ $0x0000000000000001, CX 57 | 58 | affine_lookup_loop: 59 | MOVD CX, X1 60 | PSHUFD $0x00, X1, X1 61 | PCMPEQL X0, X1 62 | MOVOU (AX), X10 63 | MOVOU 16(AX), X11 64 | MOVOU 32(AX), X12 65 | MOVOU 48(AX), X13 66 | PAND X1, X10 67 | PAND X1, X11 68 | PAND X1, X12 69 | PAND X1, X13 70 | POR X10, X2 71 | POR X11, X3 72 | POR X12, X4 73 | POR X13, X5 74 | MOVOU 64(AX), X10 75 | MOVOU 80(AX), X11 76 | MOVOU 88(AX), X12 77 | MOVOU 104(AX), X13 78 | PAND X1, X10 79 | PAND X1, X11 80 | PAND X1, X12 81 | PAND X1, X13 82 | POR X10, X6 83 | POR X11, X7 84 | POR X12, X8 85 | POR X13, X9 86 | ADDQ $0x78, AX 87 | INCQ CX 88 | CMPQ CX, $0x08 89 | JLE affine_lookup_loop 90 | 91 | // Write out the result 92 | MOVQ out+8(FP), AX 93 | MOVOU X2, (AX) 94 | MOVOU X3, 16(AX) 95 | MOVOU X4, 32(AX) 96 | MOVOU X5, 48(AX) 97 | MOVOU X6, 64(AX) 98 | MOVOU X7, 80(AX) 99 | MOVOU X8, 88(AX) 100 | MOVOU X9, 104(AX) 101 | RET 102 | 103 | DATA cached_id_0<>+0(SB)/4, $0x0001db2f 104 | DATA cached_id_0<>+4(SB)/4, $0x0001db42 105 | DATA cached_id_0<>+8(SB)/4, $0x00000000 106 | DATA cached_id_0<>+12(SB)/4, $0x00000000 107 | DATA cached_id_0<>+16(SB)/4, $0x0003b684 108 | DATA cached_id_0<>+20(SB)/4, $0x03ffffed 109 | DATA cached_id_0<>+24(SB)/4, $0x00000000 110 | DATA cached_id_0<>+28(SB)/4, $0x01ffffff 111 | GLOBL cached_id_0<>(SB), RODATA|NOPTR, $32 112 | 113 | DATA cached_id_1<>+0(SB)/4, $0x04000000 114 | DATA cached_id_1<>+4(SB)/4, $0x00000000 115 | DATA cached_id_1<>+8(SB)/4, $0x01ffffff 116 | DATA cached_id_1<>+12(SB)/4, $0x00000000 117 | DATA cached_id_1<>+16(SB)/4, $0x00000000 118 | DATA cached_id_1<>+20(SB)/4, $0x03ffffff 119 | DATA cached_id_1<>+24(SB)/4, $0x00000000 120 | DATA cached_id_1<>+28(SB)/4, $0x01ffffff 121 | GLOBL cached_id_1<>(SB), RODATA|NOPTR, $32 122 | 123 | DATA cached_id_2_4<>+0(SB)/4, $0x03ffffff 124 | DATA cached_id_2_4<>+4(SB)/4, $0x00000000 125 | DATA cached_id_2_4<>+8(SB)/4, $0x01ffffff 126 | DATA cached_id_2_4<>+12(SB)/4, $0x00000000 127 | DATA cached_id_2_4<>+16(SB)/4, $0x00000000 128 | DATA cached_id_2_4<>+20(SB)/4, $0x03ffffff 129 | DATA cached_id_2_4<>+24(SB)/4, $0x00000000 130 | DATA cached_id_2_4<>+28(SB)/4, $0x01ffffff 131 | GLOBL cached_id_2_4<>(SB), RODATA|NOPTR, $32 132 | 133 | // func lookupCached(table *cachedPointLookupTable, out *cachedPoint, xabs uint8) 134 | // Requires: AVX, AVX2 135 | TEXT ·lookupCached(SB), NOSPLIT|NOFRAME, $0-17 136 | MOVQ table+0(FP), AX 137 | 138 | // Build the mask, zero all the registers 139 | MOVBQZX xabs+16(FP), CX 140 | VMOVD CX, X0 141 | VPBROADCASTD X0, Y0 142 | VPXOR Y2, Y2, Y2 143 | VPXOR Y3, Y3, Y3 144 | VPXOR Y4, Y4, Y4 145 | VPXOR Y5, Y5, Y5 146 | VPXOR Y6, Y6, Y6 147 | 148 | // 0: Identity element 149 | VPXOR Y1, Y1, Y1 150 | VPCMPEQD Y0, Y1, Y1 151 | VMOVDQA cached_id_0<>+0(SB), Y7 152 | VMOVDQA cached_id_1<>+0(SB), Y8 153 | VMOVDQA cached_id_2_4<>+0(SB), Y9 154 | VMOVDQA Y9, Y10 155 | VMOVDQA Y9, Y11 156 | VPAND Y7, Y1, Y2 157 | VPAND Y8, Y1, Y3 158 | VPAND Y9, Y1, Y4 159 | VPAND Y10, Y1, Y5 160 | VPAND Y11, Y1, Y6 161 | 162 | // 1 .. 8 163 | MOVQ $0x0000000000000001, CX 164 | 165 | cached_lookup_loop: 166 | VMOVQ CX, X1 167 | VPBROADCASTD X1, Y1 168 | VPCMPEQD Y0, Y1, Y1 169 | VPAND (AX), Y1, Y7 170 | VPAND 32(AX), Y1, Y8 171 | VPAND 64(AX), Y1, Y9 172 | VPAND 96(AX), Y1, Y10 173 | VPAND 128(AX), Y1, Y11 174 | VPOR Y2, Y7, Y2 175 | VPOR Y3, Y8, Y3 176 | VPOR Y4, Y9, Y4 177 | VPOR Y5, Y10, Y5 178 | VPOR Y6, Y11, Y6 179 | ADDQ $0xa0, AX 180 | INCQ CX 181 | CMPQ CX, $0x08 182 | JLE cached_lookup_loop 183 | 184 | // Write out the result 185 | MOVQ out+8(FP), AX 186 | VMOVDQU Y2, (AX) 187 | VMOVDQU Y3, 32(AX) 188 | VMOVDQU Y4, 64(AX) 189 | VMOVDQU Y5, 96(AX) 190 | VMOVDQU Y6, 128(AX) 191 | VZEROUPPER 192 | RET 193 | -------------------------------------------------------------------------------- /curve/window_generic.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2019 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | //go:build !amd64 || purego || force32bit 33 | 34 | package curve 35 | 36 | import "github.com/oasisprotocol/curve25519-voi/internal/subtle" 37 | 38 | func lookupAffineNiels(tbl *affineNielsPointLookupTable, out *affineNielsPoint, xabs uint8) { 39 | out.Identity() 40 | for j := 1; j < 9; j++ { 41 | // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. 42 | c := subtle.ConstantTimeCompareByte(byte(xabs), byte(j)) 43 | out.ConditionalAssign(&tbl[j-1], c) 44 | } 45 | } 46 | 47 | func lookupCached(table *cachedPointLookupTable, out *cachedPoint, xabs uint8) { 48 | panic(errVectorNotSupported) 49 | } 50 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/oasisprotocol/curve25519-voi 2 | 3 | go 1.17 4 | 5 | require ( 6 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 7 | golang.org/x/sys v0.0.0-20220325203850-36772127a21f 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s= 2 | golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 3 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 4 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 5 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 6 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 7 | golang.org/x/sys v0.0.0-20220325203850-36772127a21f h1:TrmogKRsSOxRMJbLYGrB4SBbW+LJcEllYBLME5Zk5pU= 8 | golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 9 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 10 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 11 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 12 | -------------------------------------------------------------------------------- /internal/asm/amd64/common.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //nolint:deadcode,unused 31 | package main 32 | 33 | import ( 34 | "fmt" 35 | 36 | . "github.com/mmcloughlin/avo/build" 37 | "github.com/mmcloughlin/avo/buildtags" 38 | . "github.com/mmcloughlin/avo/operand" 39 | ) 40 | 41 | // Stub types to make the avo function signature parser behave without 42 | // having to introduce avo as a dependency for the actual package. 43 | type ( 44 | affineNielsPointLookupTable struct{} 45 | affineNielsPoint struct{} 46 | 47 | Element struct{} 48 | 49 | cachedPointLookupTable struct{} 50 | cachedPoint struct{} 51 | extendedPoint struct{} 52 | fieldElement2625x4 struct{} 53 | ) 54 | 55 | // SetCommon sets the common file-level properties that are expected for all 56 | // assembly files. 57 | func SetCommon() error { 58 | // Use our stub types so we can declare nice function prototypes. 59 | Package(".") 60 | 61 | // We want `go:build amd64,!purego,!force32bit` 62 | c, err := buildtags.ParseConstraint("amd64,!purego,!force32bit") 63 | if err != nil { 64 | return fmt.Errorf("asm/amd64: failed to parse build constraint: %w", err) 65 | } 66 | Constraints(c) 67 | 68 | return nil 69 | } 70 | 71 | func newU32x8(name string, values [8]uint32) Mem { 72 | ref := GLOBL(name, RODATA|NOPTR) 73 | for i, v := range values { 74 | DATA(i*4, U32(v)) 75 | } 76 | return ref 77 | } 78 | 79 | func newU64x4(name string, values [4]uint64) Mem { 80 | ref := GLOBL(name, RODATA|NOPTR) 81 | for i, v := range values { 82 | DATA(i*8, U64(v)) 83 | } 84 | return ref 85 | } 86 | 87 | func MM_SHUFFLE(z, y, x, w uint8) Constant { 88 | return U8(z<<6 | y<<4 | x<<2 | w<<0) 89 | } 90 | -------------------------------------------------------------------------------- /internal/asm/amd64/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | go run field_u64.go common.go > ../../field/field_u64_amd64.s 3 | go run window.go common.go > ../../../curve/window_amd64.s 4 | go run edwards_vector.go common.go > ../../../curve/edwards_vector_amd64.s 5 | -------------------------------------------------------------------------------- /internal/asm/amd64/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/oasisprotocol/curve25519-voi/internal/asm/amd64 2 | 3 | go 1.17 4 | 5 | require github.com/mmcloughlin/avo v0.4.0 6 | 7 | require ( 8 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect 9 | golang.org/x/sys v0.0.0-20220325203850-36772127a21f // indirect 10 | golang.org/x/tools v0.1.10 // indirect 11 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 12 | ) 13 | -------------------------------------------------------------------------------- /internal/asm/amd64/go.sum: -------------------------------------------------------------------------------- 1 | github.com/mmcloughlin/avo v0.4.0 h1:jeHDRktVD+578ULxWpQHkilor6pkdLF7u7EiTzDbfcU= 2 | github.com/mmcloughlin/avo v0.4.0/go.mod h1:RW9BfYA3TgO9uCdNrKU2h6J8cPD8ZLznvfgHAeszb1s= 3 | github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 4 | github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 5 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 6 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 7 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 8 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 9 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 10 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= 11 | golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= 12 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 13 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 14 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 15 | golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 16 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 17 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 18 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 19 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 20 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 21 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 22 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 23 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 24 | golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 25 | golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 26 | golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 27 | golang.org/x/sys v0.0.0-20220325203850-36772127a21f h1:TrmogKRsSOxRMJbLYGrB4SBbW+LJcEllYBLME5Zk5pU= 28 | golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 29 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 30 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 31 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 32 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 33 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 34 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 35 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 36 | golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= 37 | golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= 38 | golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= 39 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 40 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 41 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= 42 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 43 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 44 | -------------------------------------------------------------------------------- /internal/disalloweq/disalloweq.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Package disalloweq provides a method for disallowing struct comparisons 31 | // with the `==` operator. 32 | package disalloweq 33 | 34 | // DisallowEqual can be used to cause the compiler to reject attempts to 35 | // compare structs with the `==` operator. 36 | // 37 | // This is useful as the Scalar and FieldElement types should not be 38 | // comparable via the `==` operator as the internal representation of 39 | // both are not guaranteed to be canonical (ie: fully reduced). 40 | // 41 | // The better solution would be for Go to embrace circa 1960s technology 42 | // and support operator overloading a la ALGOL 68. 43 | // 44 | // See: https://twitter.com/bradfitz/status/860145039573385216 45 | type DisallowEqual [0]func() 46 | -------------------------------------------------------------------------------- /internal/elligator/constants_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package elligator 31 | 32 | import ( 33 | "encoding/binary" 34 | "testing" 35 | 36 | "github.com/oasisprotocol/curve25519-voi/internal/field" 37 | ) 38 | 39 | func TestConstants(t *testing.T) { 40 | t.Run("A", testConstantsA) 41 | t.Run("NegA", testConstantsNegA) 42 | t.Run("ASquared", testConstantsASquared) 43 | t.Run("SqrtNegAPlusTwo", testConstantsSqrtNegAPlusTwo) 44 | t.Run("UFactor", testConstantsUFactor) 45 | t.Run("VFactor", testConstantsVFactor) 46 | } 47 | 48 | func testConstantsA(t *testing.T) { 49 | expected := feFromUint64(486662) 50 | 51 | if constMONTGOMERY_A.Equal(expected) != 1 { 52 | t.Fatalf("A != 486662 (Got: %v)", constMONTGOMERY_A) 53 | } 54 | } 55 | 56 | func testConstantsNegA(t *testing.T) { 57 | expected := new(field.Element).Neg(&constMONTGOMERY_A) 58 | 59 | if constMONTGOMERY_NEG_A.Equal(expected) != 1 { 60 | t.Fatalf("NEG_A != -A (Got: %v)", constMONTGOMERY_NEG_A) 61 | } 62 | } 63 | 64 | func testConstantsASquared(t *testing.T) { 65 | var expected field.Element 66 | expected.Square(&constMONTGOMERY_A) 67 | 68 | if constMONTGOMERY_A_SQUARED.Equal(&expected) != 1 { 69 | t.Fatalf("A_SQUARED != A^2 (Got: %v)", constMONTGOMERY_A_SQUARED) 70 | } 71 | } 72 | 73 | func testConstantsSqrtNegAPlusTwo(t *testing.T) { 74 | var expected field.Element 75 | expected.Sub(&constMONTGOMERY_NEG_A, &field.Two) 76 | expected.Invert(&expected) 77 | expected.InvSqrt() 78 | 79 | if constMONTGOMERY_SQRT_NEG_A_PLUS_TWO.Equal(&expected) != 1 { 80 | t.Fatalf("SQRT_NEG_A_PLUS_TWO != sqrt(-(A+2)) (Got: %v)", constMONTGOMERY_SQRT_NEG_A_PLUS_TWO) 81 | } 82 | } 83 | 84 | func testConstantsUFactor(t *testing.T) { 85 | var expected field.Element 86 | expected.Neg(&field.Two) 87 | expected.Mul(&expected, &field.SQRT_M1) 88 | 89 | if constMONTGOMERY_U_FACTOR.Equal(&expected) != 1 { 90 | t.Fatalf("U_FACTOR != -2 * sqrt(-1) (Got: %v)", constMONTGOMERY_U_FACTOR) 91 | } 92 | } 93 | 94 | func testConstantsVFactor(t *testing.T) { 95 | var expected field.Element 96 | expected.Invert(&constMONTGOMERY_U_FACTOR) 97 | expected.InvSqrt() 98 | 99 | if constMONTGOMERY_V_FACTOR.Equal(&expected) != 1 { 100 | t.Fatalf("V_FACTOR != sqrt(u_factor) (Got: %v)", constMONTGOMERY_V_FACTOR) 101 | } 102 | } 103 | 104 | func feFromUint64(x uint64) *field.Element { 105 | var feBytes [field.ElementSize]byte 106 | binary.LittleEndian.PutUint64(feBytes[0:8], x) 107 | 108 | var fe field.Element 109 | _, _ = fe.SetBytes(feBytes[:]) 110 | return &fe 111 | } 112 | -------------------------------------------------------------------------------- /internal/elligator/constants_u32.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build (386 || arm || mips || mipsle || wasm || mips64le || mips64 || riscv64 || loong64 || force32bit) && !force64bit 31 | 32 | package elligator 33 | 34 | import "github.com/oasisprotocol/curve25519-voi/internal/field" 35 | 36 | var ( 37 | // A = 486662 38 | constMONTGOMERY_A = field.NewElement2625(486662, 0, 0, 0, 0, 0, 0, 0, 0, 0) 39 | 40 | // NEG_A = -A 41 | constMONTGOMERY_NEG_A = field.NewElement2625( 42 | 66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 43 | 33554431, 44 | ) 45 | 46 | // A_SQUARED = A^2 47 | constMONTGOMERY_A_SQUARED = field.NewElement2625(12721188, 3529, 0, 0, 0, 0, 0, 0, 0, 0) 48 | 49 | // SQRT_NEG_A_PLUS_TWO = sqrt(-(A+2)) 50 | constMONTGOMERY_SQRT_NEG_A_PLUS_TWO = field.NewElement2625( 51 | 54885894, 25242303, 55597453, 9067496, 51808079, 33312638, 25456129, 14121551, 54921728, 52 | 3972023, 53 | ) 54 | 55 | // U_FACTOR = -2 * sqrt(-1) 56 | constMONTGOMERY_U_FACTOR = field.NewElement2625( 57 | 65191565, 15887450, 48352964, 26553601, 42329919, 544945, 50292418, 4011308, 66455492, 58 | 10741467, 59 | ) 60 | 61 | // V_FACTOR = sqrt(U_FACTOR) 62 | constMONTGOMERY_V_FACTOR = field.NewElement2625( 63 | 32595774, 7943725, 57730914, 30054016, 54719391, 272472, 25146209, 2005654, 66782178, 64 | 22147949, 65 | ) 66 | ) 67 | -------------------------------------------------------------------------------- /internal/elligator/constants_u64.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build (amd64 || arm64 || ppc64le || ppc64 || s390x || force64bit) && !force32bit 31 | 32 | package elligator 33 | 34 | import "github.com/oasisprotocol/curve25519-voi/internal/field" 35 | 36 | var ( 37 | // A = 486662 38 | constMONTGOMERY_A = field.NewElement51(486662, 0, 0, 0, 0) 39 | 40 | // NEG_A = -A 41 | constMONTGOMERY_NEG_A = field.NewElement51( 42 | 2251799813198567, 43 | 2251799813685247, 44 | 2251799813685247, 45 | 2251799813685247, 46 | 2251799813685247, 47 | ) 48 | 49 | // A_SQUARED = A^2 50 | constMONTGOMERY_A_SQUARED = field.NewElement51(236839902244, 0, 0, 0, 0) 51 | 52 | // SQRT_NEG_A_PLUS_TWO = sqrt(-(A+2)) 53 | constMONTGOMERY_SQRT_NEG_A_PLUS_TWO = field.NewElement51( 54 | 1693982333959686, 55 | 608509411481997, 56 | 2235573344831311, 57 | 947681270984193, 58 | 266558006233600, 59 | ) 60 | 61 | // U_FACTOR = -2 * sqrt(-1) 62 | constMONTGOMERY_U_FACTOR = field.NewElement51( 63 | 1066188786548365, 64 | 1781982046572228, 65 | 36570682222399, 66 | 269194373326530, 67 | 720847714518980, 68 | ) 69 | 70 | // V_FACTOR = sqrt(U_FACTOR) 71 | constMONTGOMERY_V_FACTOR = field.NewElement51( 72 | 533094393274174, 73 | 2016890930128738, 74 | 18285341111199, 75 | 134597186663265, 76 | 1486323764102114, 77 | ) 78 | ) 79 | -------------------------------------------------------------------------------- /internal/elligator/elligator2.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package elligator 31 | 32 | import ( 33 | "github.com/oasisprotocol/curve25519-voi/curve" 34 | "github.com/oasisprotocol/curve25519-voi/internal/field" 35 | ) 36 | 37 | var constFieldZero field.Element 38 | 39 | // SetEdwardsFromXY sets the EdwardsPoint to that corresponding to the x 40 | // and y coordinates. 41 | func SetEdwardsFromXY(p *curve.EdwardsPoint, x, y *field.Element) *curve.EdwardsPoint { 42 | // While being able to create a curve.EdwardsPoint from the x and y 43 | // coordinate (`(x, y, 1, x*y)`) than doing decompression, not having 44 | // to have something ugly like EdwardsPoint.InternalSetXY that exposes 45 | // the presence of the internal field package is probably better. 46 | var pCompressed curve.CompressedEdwardsY 47 | _ = y.ToBytes(pCompressed[:]) 48 | pCompressed[31] ^= byte(x.IsNegative()) << 7 49 | 50 | // EdwardsFlavor ensures that this cannot fail. 51 | if _, err := p.SetCompressedY(&pCompressed); err != nil { 52 | panic("internal/elligator: failed to decompress point: " + err.Error()) 53 | } 54 | 55 | return p 56 | } 57 | 58 | // EdwardsFlavor computes EdwardsPoint corresponding to the provided Elligator 2 59 | // representative. 60 | func EdwardsFlavor(r *field.Element) *curve.EdwardsPoint { 61 | u, v := montgomeryFlavor(r) 62 | 63 | // Per RFC 7748: (x, y) = (sqrt(-486664)*u/v, (u-1)/(u+1)) 64 | 65 | var x field.Element 66 | x.Invert(&v) 67 | x.Mul(&x, &u) 68 | x.Mul(&x, &constMONTGOMERY_SQRT_NEG_A_PLUS_TWO) 69 | 70 | var uMinusOne, uPlusOne, y field.Element 71 | uMinusOne.Sub(&u, &field.One) 72 | uPlusOne.Add(&u, &field.One) 73 | uPlusOneIsZero := uPlusOne.IsZero() 74 | uPlusOne.Invert(&uPlusOne) 75 | y.Mul(&uMinusOne, &uPlusOne) 76 | 77 | // This does something slightly different than EdwardsPoint.SetMontgomery 78 | // as that conversion routine bails if u == -1. However the hash-to-curve 79 | // specification for this mapping requires: 80 | // 81 | // This mapping is undefined when t == 0 or s == -1, i.e., when the 82 | // denominator of either of the above rational functions is zero. 83 | // Implementations MUST detect exceptional cases and return the value 84 | // (v, w) = (0, 1), which is the identity point on all twisted Edwards 85 | // curves. 86 | resultUndefined := uPlusOneIsZero | v.IsZero() 87 | x.ConditionalAssign(&constFieldZero, resultUndefined) 88 | y.ConditionalAssign(&field.One, resultUndefined) 89 | 90 | var p curve.EdwardsPoint 91 | return SetEdwardsFromXY(&p, &x, &y) 92 | } 93 | 94 | // montgomeryFlavor computes Montgomery u and v coordinates corresponding 95 | // to the provided Elligator 2 representative. 96 | func montgomeryFlavor(r *field.Element) (field.Element, field.Element) { 97 | // This is based off the public domain python implementation by 98 | // Loup Vaillant, taken from the Monocypher package 99 | // (tests/gen/elligator.py). 100 | // 101 | // The choice of base implementation is primarily because it was 102 | // convenient, and because they appear to be one of the people 103 | // that have given the most thought regarding how to implement 104 | // this correctly, with a readable implementation that I can 105 | // wrap my brain around. 106 | 107 | var ( 108 | t1, t2, t3, u, v field.Element 109 | isSquare int 110 | ) 111 | 112 | t1.Square2(r) // r1 113 | u.Add(&t1, &field.One) // r2 114 | t2.Square(&u) 115 | 116 | t3.Mul(&constMONTGOMERY_A_SQUARED, &t1) // numerator 117 | t3.Sub(&t3, &t2) 118 | t3.Mul(&t3, &constMONTGOMERY_A) 119 | 120 | t1.Mul(&t2, &u) // denominator 121 | 122 | t1.Mul(&t1, &t3) 123 | _, isSquare = t1.InvSqrt() 124 | 125 | u.Square(r) 126 | u.Mul(&u, &constMONTGOMERY_U_FACTOR) 127 | 128 | v.Mul(r, &constMONTGOMERY_V_FACTOR) 129 | 130 | u.ConditionalAssign(&field.One, isSquare) 131 | v.ConditionalAssign(&field.One, isSquare) 132 | 133 | v.Mul(&v, &t3) 134 | v.Mul(&v, &t1) 135 | 136 | t1.Square(&t1) 137 | 138 | u.Mul(&u, &constMONTGOMERY_NEG_A) 139 | u.Mul(&u, &t3) 140 | u.Mul(&u, &t2) 141 | u.Mul(&u, &t1) 142 | 143 | v.ConditionalNegate(isSquare ^ v.IsNegative()) 144 | 145 | return u, v 146 | } 147 | -------------------------------------------------------------------------------- /internal/field/constants_u32.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | //go:build (386 || arm || mips || mipsle || wasm || mips64le || mips64 || riscv64 || loong64 || force32bit) && !force64bit 32 | 33 | package field 34 | 35 | // Precomputed value of one of the square roots of -1 (mod p). 36 | var SQRT_M1 = NewElement2625( 37 | 34513072, 25610706, 9377949, 3500415, 12389472, 38 | 33281959, 41962654, 31548777, 326685, 11406482, 39 | ) 40 | 41 | // `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) 42 | var constAPLUS2_OVER_FOUR = NewElement2625(121666, 0, 0, 0, 0, 0, 0, 0, 0, 0) 43 | -------------------------------------------------------------------------------- /internal/field/constants_u64.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2019 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | //go:build (amd64 || arm64 || ppc64le || ppc64 || s390x || force64bit) && !force32bit 32 | 33 | package field 34 | 35 | // Precomputed value of one of the square roots of -1 (mod p). 36 | var SQRT_M1 = NewElement51( 37 | 1718705420411056, 38 | 234908883556509, 39 | 2233514472574048, 40 | 2117202627021982, 41 | 765476049583133, 42 | ) 43 | -------------------------------------------------------------------------------- /internal/field/field_u64_amd64.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build amd64 && !purego && !force32bit 31 | 32 | package field 33 | 34 | //go:noescape 35 | func feMul(out, a, b *Element) 36 | 37 | //go:noescape 38 | func fePow2k(out, a *Element, k uint) 39 | -------------------------------------------------------------------------------- /internal/field/field_u64_generic.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build (purego || (!amd64 && force64bit) || arm64 || ppc64le || ppc64 || s390x) && !force32bit 31 | 32 | package field 33 | 34 | func feMul(fe, a, b *Element) { 35 | feMulGeneric(fe, a, b) 36 | } 37 | 38 | func fePow2k(fe, t *Element, k uint) { 39 | fePow2kGeneric(fe, t, k) 40 | } 41 | -------------------------------------------------------------------------------- /internal/lattice/int128.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package lattice 31 | 32 | import ( 33 | "encoding/binary" 34 | "math/bits" 35 | 36 | "github.com/oasisprotocol/curve25519-voi/curve/scalar" 37 | ) 38 | 39 | // This is shamelessly stolen from https://github.com/ryanavella/wide 40 | // which is available under the UNLICENSE public domain dedication, 41 | // with the following notable alterations: 42 | // 43 | // * `IsNeg` renamed to `IsNegative` to match conventions in the rest 44 | // of the module. 45 | // * `ToScalar`, `isZero` added. 46 | // * Methods that do not need to be public, are now private. 47 | // * Methods altered to use `math/bits` intrinsics. 48 | // 49 | // Note: The consumers of this API and it's outputs do not require 50 | // things to be constant-time. 51 | 52 | const ( 53 | int64Size = 64 54 | int128Size = 128 55 | ) 56 | 57 | var ( 58 | i128Zero Int128 59 | i128One = Int128{lo: 1} 60 | ) 61 | 62 | // Int128 is a representation of a signed 128-bit integer. 63 | type Int128 struct { 64 | hi int64 65 | lo uint64 66 | } 67 | 68 | // ToScalar sets the scalar to the Int128, honoring the sign. 69 | func (x Int128) ToScalar(s *scalar.Scalar) *scalar.Scalar { 70 | xAbs := x.Abs() 71 | 72 | var b [scalar.ScalarSize]byte 73 | binary.LittleEndian.PutUint64(b[0:8], xAbs.lo) 74 | binary.LittleEndian.PutUint64(b[8:16], uint64(xAbs.hi)) 75 | 76 | if _, err := s.SetBits(b[:]); err != nil { 77 | panic("internal/lattice: failed to serialize int128 as scalar: " + err.Error()) 78 | } 79 | if x.IsNegative() { 80 | s.Neg(s) 81 | } 82 | 83 | return s 84 | } 85 | 86 | // IsNegative returns whether or not the Int128 is negative. 87 | func (x Int128) IsNegative() bool { 88 | return x.hi < 0 89 | } 90 | 91 | // Abs returns the absolute value of an Int128. 92 | func (x Int128) Abs() Int128 { 93 | if x.IsNegative() { 94 | return x.neg() 95 | } 96 | return x 97 | } 98 | 99 | // isZero returns whether or not the Int128 is zero. 100 | func (x Int128) isZero() bool { 101 | return x.hi == 0 && x.lo == 0 102 | } 103 | 104 | // neg returns the additive inverse of an Int128. 105 | func (x Int128) neg() (z Int128) { 106 | z = z.sub(x) 107 | return z 108 | } 109 | 110 | // add returns the sum of two Int128's 111 | func (x Int128) add(y Int128) (z Int128) { 112 | var carryOut uint64 113 | z.lo, carryOut = bits.Add64(x.lo, y.lo, 0) 114 | z.hi = x.hi + y.hi + int64(carryOut) 115 | return z 116 | } 117 | 118 | // sub returns the difference of two Int128's 119 | func (x Int128) sub(y Int128) (z Int128) { 120 | var borrowOut uint64 121 | z.lo, borrowOut = bits.Sub64(x.lo, y.lo, 0) 122 | z.hi = x.hi - (y.hi + int64(borrowOut)) 123 | return z 124 | } 125 | 126 | // shl returns an Int128 left-shifted by a uint (i.e. x << n). 127 | func (x Int128) shl(n uint) (z Int128) { 128 | switch { 129 | case n >= int128Size: 130 | return z // z.hi, z.lo = 0, 0 131 | case n >= int64Size: 132 | z.hi = int64(x.lo << (n - int64Size)) 133 | z.lo = 0 134 | return z 135 | default: 136 | z.hi = int64(uint64(x.hi)<>(int64Size-n)) 137 | z.lo = x.lo << n 138 | return z 139 | } 140 | } 141 | 142 | func newInt128(hi int64, lo uint64) Int128 { 143 | return Int128{hi: hi, lo: lo} 144 | } 145 | 146 | func newInt128FromScalar(s *scalar.Scalar) Int128 { 147 | var b [scalar.ScalarSize]byte 148 | if err := s.ToBytes(b[:]); err != nil { 149 | panic("internal/lattice: failed to serialize scalar as int128: " + err.Error()) 150 | } 151 | 152 | return Int128{ 153 | hi: int64(binary.LittleEndian.Uint64(b[8:16])), 154 | lo: binary.LittleEndian.Uint64(b[0:8]), 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /internal/lattice/lattice_reduction.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Jack Grigg. All rights reserved. 2 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | package lattice 32 | 33 | import "github.com/oasisprotocol/curve25519-voi/curve/scalar" 34 | 35 | var constELL_LOWER_HALF = newInt128(0x14def9dea2f79cd6, 0x5812631a5cf5d3ed) 36 | 37 | // FindShortVector finds a "short" non-zero vector `(d_0, d_1)` such that 38 | // `d_0 = d_1 k mod ell`. `d_0` and `d_1` may be negative. 39 | // 40 | // Implements Algorithm 4 from [Pornin 2020](https://eprint.iacr.org/2020/454). 41 | func FindShortVector(k *scalar.Scalar) (Int128, Int128) { 42 | N_u_512 := ellSquared() 43 | 44 | N_v_512 := (&int512{}).Mul(k, k) 45 | N_v_512 = N_v_512.Add(N_v_512, i512One) 46 | 47 | p_512 := (&int512{}).Mul(scalar.BASEPOINT_ORDER, k) 48 | 49 | // The target bit-length of `N_v` for the vector to be considered short. 50 | const T = 254 // len(ell) + 1 51 | 52 | u_0, u_1 := constELL_LOWER_HALF, i128Zero 53 | v_0, v_1 := newInt128FromScalar(k), i128One 54 | 55 | // Like described in the paper under "Implementation Notes and Benchmarks", 56 | // this is implemented in two passes, one with 512-bit integers, and one 57 | // with 384-bit integers, leveraging the fact that N_u, N_v and p will 58 | // continually decrease in size. 59 | // 60 | // One would think that the duplication of the algorithm could be 61 | // eliminated by defining a bigInt interface, and they would be right. 62 | // However doing so comes at the cost of 6 heap allocations, and a 25% 63 | // performance penalty, at which point we are better off not bothering 64 | // to shrink the representations in the first place. 65 | 66 | // 67 | // Pass 1: N_u, N_v, p are stored in 512-bit integers. 68 | // 69 | 70 | for { 71 | if N_u_512.PositiveLt(N_v_512) { // N_u < N_v 72 | u_0, v_0 = v_0, u_0 73 | u_1, v_1 = v_1, u_1 74 | N_u_512, N_v_512 = N_v_512, N_u_512 75 | } 76 | 77 | // N_u is the largest out of N_u, N_v, and p. N_u and N_v are 78 | // always positive, however p can be negative. So if N_u fits 79 | // into 383 bits, then it is safe to store everything in a 80 | // 384-bit integer, since |p| <= N_u and provisions are made 81 | // as part of the check for the sign bit. 82 | if N_u_512.SafeToShrink() { 83 | break 84 | } 85 | 86 | len_N_v := N_v_512.BitLen() 87 | if len_N_v <= T { 88 | return v_0, v_1 89 | } 90 | 91 | var s uint 92 | if len_p := p_512.BitLen(); len_p > len_N_v { 93 | s = len_p - len_N_v 94 | } 95 | 96 | if !p_512.IsNegative() { 97 | u_0 = u_0.sub(v_0.shl(s)) 98 | u_1 = u_1.sub(v_1.shl(s)) 99 | 100 | N_u_512.AddShifted(N_u_512, N_v_512, 2*s) 101 | N_u_512.SubShifted(N_u_512, p_512, s+1) 102 | p_512.SubShifted(p_512, N_v_512, s) 103 | } else { 104 | u_0 = u_0.add(v_0.shl(s)) 105 | u_1 = u_1.add(v_1.shl(s)) 106 | 107 | N_u_512.AddShifted(N_u_512, N_v_512, 2*s) 108 | N_u_512.AddShifted(N_u_512, p_512, s+1) 109 | p_512.AddShifted(p_512, N_v_512, s) 110 | } 111 | } 112 | 113 | // 114 | // Pass 2: N_u, N_v, and p are store in 384-bit integers. 115 | // 116 | 117 | N_u_384 := (&int384{}).FromInt512(N_u_512) 118 | N_v_384 := (&int384{}).FromInt512(N_v_512) 119 | p_384 := (&int384{}).FromInt512(p_512) 120 | 121 | for { 122 | if N_u_384.PositiveLt(N_v_384) { 123 | u_0, v_0 = v_0, u_0 124 | u_1, v_1 = v_1, u_1 125 | N_u_384, N_v_384 = N_v_384, N_u_384 126 | } 127 | 128 | len_N_v := N_v_384.BitLen() 129 | if len_N_v <= T { 130 | return v_0, v_1 131 | } 132 | 133 | var s uint 134 | if len_p := p_384.BitLen(); len_p > len_N_v { 135 | s = len_p - len_N_v 136 | } 137 | 138 | if !p_384.IsNegative() { 139 | u_0 = u_0.sub(v_0.shl(s)) 140 | u_1 = u_1.sub(v_1.shl(s)) 141 | 142 | N_u_384.AddShifted(N_u_384, N_v_384, 2*s) 143 | N_u_384.SubShifted(N_u_384, p_384, s+1) 144 | p_384.SubShifted(p_384, N_v_384, s) 145 | } else { 146 | u_0 = u_0.add(v_0.shl(s)) 147 | u_1 = u_1.add(v_1.shl(s)) 148 | 149 | N_u_384.AddShifted(N_u_384, N_v_384, 2*s) 150 | N_u_384.AddShifted(N_u_384, p_384, s+1) 151 | p_384.AddShifted(p_384, N_v_384, s) 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /internal/lattice/lattice_reduction_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Jack Grigg. All rights reserved. 2 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright 12 | // notice, this list of conditions and the following disclaimer in the 13 | // documentation and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 22 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 25 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | package lattice 32 | 33 | import ( 34 | "crypto/rand" 35 | "testing" 36 | 37 | "github.com/oasisprotocol/curve25519-voi/curve/scalar" 38 | ) 39 | 40 | func TestLatticeReduction(t *testing.T) { 41 | for i := 0; i < 500; i++ { 42 | k, err := scalar.New().SetRandom(rand.Reader) 43 | if err != nil { 44 | t.Fatalf("Failed to generate random scalar: %v", err) 45 | } 46 | 47 | d_0, d_1 := FindShortVector(k) 48 | 49 | // Ensure `d_0` and `d_1` are non-zero. 50 | if d_0.isZero() { 51 | t.Fatalf("Invariant violation, d_0 is 0") 52 | } 53 | if d_1.isZero() { 54 | t.Fatalf("Invariant violation, d_1 is 0") 55 | } 56 | 57 | // Ensure `d_0 = d_1 * k`. 58 | var s_0, s_1, should_be_d_0 scalar.Scalar 59 | d_0.ToScalar(&s_0) 60 | d_1.ToScalar(&s_1) 61 | should_be_d_0.Mul(k, &s_1) 62 | if s_0.Equal(&should_be_d_0) != 1 { 63 | t.Fatalf("d_0 != k * d_1 (Got: %v)", should_be_d_0) 64 | } 65 | } 66 | } 67 | 68 | func BenchmarkLatticeReduction(b *testing.B) { 69 | b.ReportAllocs() 70 | 71 | for i := 0; i < b.N; i++ { 72 | // Rerandomize the scalar on each iteration, and hope that enough 73 | // iterations happen to give a good estimate of average runtime. 74 | b.StopTimer() 75 | k, err := scalar.New().SetRandom(rand.Reader) 76 | if err != nil { 77 | b.Fatalf("Failed to generate random scalar: %v", err) 78 | } 79 | b.StartTimer() 80 | 81 | _, _ = FindShortVector(k) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /internal/scalar128/scalar128.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Package scalar128 implements the fast generation of random 128-bit 31 | // scalars for the purpose of batch verification. 32 | package scalar128 33 | 34 | import ( 35 | "bytes" 36 | "fmt" 37 | "io" 38 | 39 | "golang.org/x/crypto/chacha20" 40 | 41 | "github.com/oasisprotocol/curve25519-voi/curve/scalar" 42 | ) 43 | 44 | const randomizerSize = scalar.ScalarSize / 2 45 | 46 | var zeroRandomizer [scalar.ScalarSize]byte 47 | 48 | // The ideas behind this implementation is based on "Faster batch fogery 49 | // identification" (https://eprint.iacr.org/2012/549.pdf), which is basically 50 | // one of the few places where how to select an appropriate z_i is discussed. 51 | // 52 | // It turns out that even in the no-assembly (`purego`) case, calling chacha20 53 | // is more performant than reading from the system entropy source, at least 54 | // on my 64-bit Intel Linux systems. 55 | 56 | // FixRawRangeVartime adjusts the raw scalar to be in the correct range, 57 | // in variable-time. 58 | // 59 | // From the paper: 60 | // 61 | // Of course, it is also safe to simply generate z_i as a uniform 62 | // random b-bit integer, disregarding the negligible chance that 63 | // z_i == 0; but this requires minor technical modifications to 64 | // the security guarantees stated below, so we prefer to require 65 | // z != 0. 66 | // 67 | func FixRawRangeVartime(rawScalar *[scalar.ScalarSize]byte) { 68 | // From the paper: 69 | // 70 | // As precomputation we choose z_1, z_2, . . . , z_n independently 71 | // and uniformly at random from the set {1, 2, 3, . . . , 2^b}, 72 | // where b is the security level. There are several reasonable ways 73 | // to do this: for example, generate a uniform random b-bit integer 74 | // and add 1, or generate a uniform random b-bit integer and 75 | // replace 0 with 2^b. 76 | // 77 | // We go with the latter approach and replace 0 with 2^b, since 78 | // it is significantly faster for the common case. 79 | 80 | if bytes.Equal(rawScalar[:], zeroRandomizer[:]) { 81 | rawScalar[randomizerSize] = 1 82 | } 83 | } 84 | 85 | // Generator is a random 128-bit scalar generator. 86 | type Generator struct { 87 | cipher *chacha20.Cipher 88 | 89 | // Go's escape analysis insists on sticking this on the heap, if 90 | // it is declared in the function when building with `purego`, 91 | // but not if assembly is being used for chacha20. 92 | tmp [scalar.ScalarSize]byte 93 | } 94 | 95 | // SetScalarVartime sets the scalar to a random 128-bit scalar, in 96 | // variable-time. 97 | func (gen *Generator) SetScalarVartime(s *scalar.Scalar) error { 98 | // perf: This probably isn't needed, XOR-ing the previous output 99 | // with more keystream is still random. 100 | for i := range gen.tmp[:randomizerSize+1] { 101 | gen.tmp[i] = 0 102 | } 103 | 104 | gen.cipher.XORKeyStream(gen.tmp[:randomizerSize], gen.tmp[:randomizerSize]) 105 | FixRawRangeVartime(&gen.tmp) 106 | 107 | // Since the random scalar is 128-bits, there is no need to reduce. 108 | if _, err := s.SetBits(gen.tmp[:]); err != nil { 109 | return fmt.Errorf("internal/scalar128: failed to deserialize random scalar: %w", err) 110 | } 111 | 112 | return nil 113 | } 114 | 115 | // NewGenerator constructs a new random scalar generator, using entropy 116 | // from the provided source. 117 | func NewGenerator(rand io.Reader) (*Generator, error) { 118 | var ( 119 | key [chacha20.KeySize]byte 120 | nonce [chacha20.NonceSize]byte 121 | ) 122 | 123 | if _, err := io.ReadFull(rand, key[:]); err != nil { 124 | return nil, fmt.Errorf("internal/scalar128: failed to read random key: %w", err) 125 | } 126 | 127 | cipher, err := chacha20.NewUnauthenticatedCipher(key[:], nonce[:]) 128 | if err != nil { 129 | return nil, fmt.Errorf("internal/scalar128: failed initialize stream cipher: %w", err) 130 | } 131 | 132 | return &Generator{ 133 | cipher: cipher, 134 | }, nil 135 | } 136 | -------------------------------------------------------------------------------- /internal/strobe/keccakf_amd64.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 The Go Authors. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above 10 | // copyright notice, this list of conditions and the following disclaimer 11 | // in the documentation and/or other materials provided with the 12 | // distribution. 13 | // * Neither the name of Google Inc. nor the names of its 14 | // contributors may be used to endorse or promote products derived from 15 | // this software without specific prior written permission. 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | //go:build amd64 && !purego && gc 30 | 31 | package strobe 32 | 33 | import "unsafe" 34 | 35 | // This function is implemented in keccakf_amd64.s. 36 | 37 | //go:noescape 38 | 39 | func keccakF1600(state *[25]uint64) 40 | 41 | func keccakF1600Bytes(s *[25 * 8]byte) { 42 | a := (*[25]uint64)(unsafe.Pointer(&s[0])) 43 | keccakF1600(a) 44 | } 45 | -------------------------------------------------------------------------------- /internal/strobe/strobe_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package strobe 31 | 32 | import ( 33 | "bytes" 34 | "crypto/rand" 35 | "fmt" 36 | "testing" 37 | ) 38 | 39 | func TestStrobeSanity(t *testing.T) { 40 | // Generated with mimoo/StrobeGo 41 | const ( 42 | expectedHex = "c4728cdd0361684d643a44221d16dc4677c62ed74a7f103635bd9cb6f3cc11bdd8405b105cd7de36f800dda96ea52c6adab88225c44faba4281dcdf84b2f3454" 43 | expectedHex2 = "16671f5f3603853adaf55614387d5604" 44 | ) 45 | 46 | data := make([]byte, 1024) // Considerably larger than s.r 47 | for i := 0; i < len(data); i++ { 48 | b := byte(i & 0xff) 49 | data[i] = b 50 | } 51 | 52 | s := New("test-strobe-sanity") 53 | 54 | // MetaAD 55 | s.MetaAD(data, false) 56 | 57 | // KEY 58 | keyStr := "test-strobe-sanity-key" 59 | keyBuf := []byte(keyStr) 60 | s.KEY(keyBuf) 61 | if !bytes.Equal([]byte(keyStr), keyBuf) { 62 | t.Fatalf("s.KEY tramples over data: %x", keyBuf) 63 | } 64 | 65 | // Clone 66 | s2 := s.Clone() 67 | 68 | // AD 69 | s.AD(data, false) 70 | s.AD(data, true) // Test s.operate with `more` 71 | 72 | // PRF 73 | dest := make([]byte, 64) 74 | _, _ = rand.Read(dest) // Fill dest with garbage. 75 | s.PRF(dest) 76 | if x := fmt.Sprintf("%x", dest); x != expectedHex { 77 | t.Fatalf("s.PRF output mismatch: %s", x) 78 | } 79 | 80 | // PRF (cloned) 81 | dest2 := make([]byte, 16) 82 | s2.PRF(dest2) 83 | if x := fmt.Sprintf("%x", dest2); x != expectedHex2 { 84 | t.Fatalf("s2.PRF output mismatch: %s", x) 85 | } 86 | } 87 | 88 | var benchSizes = []int{1, 16, 32, 64, 128, 256, 512, 1024, 1024768} 89 | 90 | func BenchmarkStrobe(b *testing.B) { 91 | for _, sz := range benchSizes { 92 | b.Run(fmt.Sprintf("AD/%d", sz), func(b *testing.B) { 93 | benchAd(b, sz) 94 | }) 95 | } 96 | } 97 | 98 | func benchAd(b *testing.B, sz int) { 99 | buf := make([]byte, sz) 100 | _, _ = rand.Read(buf) 101 | 102 | s := New("benchmark-strobe") 103 | b.ResetTimer() 104 | 105 | b.ReportAllocs() 106 | for i := 0; i < b.N; i++ { 107 | s.AD(buf, false) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /internal/subtle/subtle.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016-2017 isis agora lovecruft. All rights reserved. 2 | // Copyright (c) 2016-2017 Henry de Valence. All rights reserved. 3 | // Copyright (c) 2020-2021 Oasis Labs Inc. All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // 1. Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // 12 | // 2. Redistributions in binary form must reproduce the above copyright 13 | // notice, this list of conditions and the following disclaimer in the 14 | // documentation and/or other materials provided with the distribution. 15 | // 16 | // 3. Neither the name of the copyright holder nor the names of its 17 | // contributors may be used to endorse or promote products derived from 18 | // this software without specific prior written permission. 19 | // 20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 23 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 26 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | package subtle 33 | 34 | import "crypto/subtle" 35 | 36 | func ConstantTimeCompareByte(a, b byte) int { 37 | return subtle.ConstantTimeByteEq(a, b) 38 | } 39 | 40 | func ConstantTimeCompareBytes(a, b []byte) int { 41 | return subtle.ConstantTimeCompare(a, b) 42 | } 43 | 44 | func ConstantTimeSelectByte(choice int, a, b byte) byte { 45 | return byte(subtle.ConstantTimeSelect(choice, int(a), int(b))) 46 | } 47 | 48 | func ConstantTimeSelectUint64(choice int, a, b uint64) uint64 { 49 | mask := uint64(-choice) 50 | return b ^ (mask & (a ^ b)) 51 | } 52 | 53 | func ConstantTimeSwapUint64(choice int, a, b *uint64) { 54 | mask := uint64(-choice) 55 | t := mask & (*a ^ *b) 56 | *a ^= t 57 | *b ^= t 58 | } 59 | 60 | func ConstantTimeSelectUint32(choice int, a, b uint32) uint32 { 61 | mask := uint32(-choice) 62 | return b ^ (mask & (a ^ b)) 63 | } 64 | 65 | func ConstantTimeSwapUint32(choice int, a, b *uint32) { 66 | mask := uint32(-choice) 67 | t := mask & (*a ^ *b) 68 | *a ^= t 69 | *b ^= t 70 | } 71 | -------------------------------------------------------------------------------- /internal/testhelpers/helpers.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package testhelpers 31 | 32 | import ( 33 | "encoding/hex" 34 | "strings" 35 | "testing" 36 | ) 37 | 38 | func MustUnhex(t *testing.T, x string) []byte { 39 | b, err := hex.DecodeString(strings.ReplaceAll(x, " ", "")) 40 | if err != nil { 41 | t.Fatalf("failed to parse hex: %v", err) 42 | } 43 | 44 | return b 45 | } 46 | -------------------------------------------------------------------------------- /internal/toolchain/compiler_is_gc.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build gc 31 | 32 | package toolchain 33 | 34 | const __SOFTWARE_REQUIRES_GC_COMPILER__ = uint8(0) 35 | -------------------------------------------------------------------------------- /internal/toolchain/constraints.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Package toolchain enforces the minimum supported toolchain. 31 | package toolchain 32 | 33 | var ( 34 | // This is enforced so that I can consolidate build constraints 35 | // instead of keeping track of exactly when each 64-bit target got 36 | // support for SSA doing the right thing for bits.Add64/bits.Mul64. 37 | // 38 | // If you absolutely must get this working on older Go versions, 39 | // the 64-bit codepath is safe (and performant) as follows: 40 | // 41 | // * 1.12 - amd64 (all other targets INSECURE due to vartime fallback) 42 | // * 1.13 - arm64, ppcle, ppc64 43 | // * 1.14 - s390x 44 | // 45 | // * riscv64 became fast during 1.19, not shipped yet 46 | // 47 | // Last updated: Go 1.19 (src/cmd/compile/internal/ssagen/ssa.go) 48 | _ = __SOFTWARE_REQUIRES_GO_VERSION_1_18__ 49 | 50 | // gccgo doesn't support Go's assembly dialect, and I don't want to 51 | // have to special case that with more build constraints either. 52 | _ = __SOFTWARE_REQUIRES_GC_COMPILER__ 53 | ) 54 | -------------------------------------------------------------------------------- /internal/toolchain/version_is_recent.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | //go:build go1.18 31 | 32 | package toolchain 33 | 34 | const __SOFTWARE_REQUIRES_GO_VERSION_1_18__ = uint8(0) 35 | -------------------------------------------------------------------------------- /internal/zeroreader/zeroreader.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 The Go Authors. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above 10 | // copyright notice, this list of conditions and the following disclaimer 11 | // in the documentation and/or other materials provided with the 12 | // distribution. 13 | // * Neither the name of Google Inc. nor the names of its 14 | // contributors may be used to endorse or promote products derived from 15 | // this software without specific prior written permission. 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | // Package zeroreader provides a io.Reader that returns all zero output. 30 | package zeroreader 31 | 32 | // ZeroReader implements an io.Reader that returns all zero output. 33 | type ZeroReader struct{} 34 | 35 | func (ZeroReader) Read(buf []byte) (int, error) { 36 | for i := range buf { 37 | buf[i] = 0 38 | } 39 | return len(buf), nil 40 | } 41 | -------------------------------------------------------------------------------- /primitives/ed25519/ed25519ph_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016 The Go Authors. All rights reserved. 2 | // Copyright (c) 2019 Oasis Labs Inc. All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package ed25519 31 | 32 | import ( 33 | "bytes" 34 | "compress/gzip" 35 | "encoding/json" 36 | "os" 37 | "testing" 38 | 39 | "github.com/oasisprotocol/curve25519-voi/internal/testhelpers" 40 | ) 41 | 42 | // This only tests Ed25519ctx, for Ed25519ph, see ed25519_test.go (testSignVerifyHashed). 43 | 44 | type ctxTestVector struct { 45 | Name string `json:"name"` 46 | SecretKey string `json:"secret_key"` 47 | PublicKey string `json:"public_key"` 48 | Message string `json:"message"` 49 | Context string `json:"context"` 50 | Signature string `json:"signature"` 51 | } 52 | 53 | func (tv *ctxTestVector) Run(t *testing.T) { 54 | // The Go representation of a raw private key includes the public 55 | // key, the RFC test vector's idea of such does not. 56 | rawPrivate := testhelpers.MustUnhex(t, tv.SecretKey+tv.PublicKey) 57 | rawPublic := testhelpers.MustUnhex(t, tv.PublicKey) 58 | 59 | privateKey := PrivateKey(rawPrivate) 60 | publicKey := privateKey.Public().(PublicKey) 61 | if !bytes.Equal(publicKey[:], rawPublic) { 62 | t.Fatalf("derived public key does not match test vectors") 63 | } 64 | 65 | msg := testhelpers.MustUnhex(t, tv.Message) 66 | ctx := testhelpers.MustUnhex(t, tv.Context) 67 | 68 | expectedSig := testhelpers.MustUnhex(t, tv.Signature) 69 | 70 | opts := &Options{ 71 | Context: string(ctx), 72 | } 73 | 74 | sig, err := privateKey.Sign(nil, msg, opts) 75 | if err != nil { 76 | t.Fatal(err) 77 | } 78 | if !bytes.Equal(sig, expectedSig) { 79 | t.Error("signature doesn't match test vector") 80 | } 81 | if !VerifyWithOptions(publicKey, msg, sig, opts) { 82 | t.Errorf("valid signature rejected") 83 | } 84 | 85 | wrongMsg := []byte("bad message" + string(msg)) 86 | if VerifyWithOptions(publicKey, wrongMsg, sig, opts) { 87 | t.Errorf("signature of different message accepted") 88 | } 89 | 90 | opts.Context = "bad context" + string(ctx) 91 | if VerifyWithOptions(publicKey, msg, sig, opts) { 92 | t.Errorf("signature with different context accepted") 93 | } 94 | } 95 | 96 | func TestSignVerifyCtx(t *testing.T) { 97 | f, err := os.Open("testdata/rfc8032_ctx.json.gz") 98 | if err != nil { 99 | t.Fatal(err) 100 | } 101 | defer f.Close() 102 | rd, err := gzip.NewReader(f) 103 | if err != nil { 104 | t.Fatal(err) 105 | } 106 | defer rd.Close() 107 | 108 | var testVectors []ctxTestVector 109 | dec := json.NewDecoder(rd) 110 | if err = dec.Decode(&testVectors); err != nil { 111 | t.Fatal(err) 112 | } 113 | 114 | for _, v := range testVectors { 115 | t.Run(v.Name, v.Run) 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /primitives/ed25519/example_batch_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package ed25519 31 | 32 | import ( 33 | "crypto/rand" 34 | "fmt" 35 | ) 36 | 37 | // ExampleBatchVerifier demonstrates batch verification functionality. 38 | func ExampleBatchVerifier() { 39 | // curve25519-voi provides batch verification, with an API that 40 | // is similar to ed25519consensus. 41 | 42 | msg1 := []byte("test message") 43 | msg2 := []byte("test message 2") 44 | msg3 := []byte("test message with a vengance") 45 | msg4 := []byte("live free or test message") 46 | msg5 := []byte("a good day to test message") 47 | 48 | publicKey, privateKey, err := GenerateKey(rand.Reader) 49 | if err != nil { 50 | panic("GenerateKey: " + err.Error()) 51 | } 52 | 53 | publicKey2, privateKey2, err := GenerateKey(rand.Reader) 54 | if err != nil { 55 | panic("GenerateKey: " + err.Error()) 56 | } 57 | 58 | sig1 := Sign(privateKey, msg1) 59 | sig2 := Sign(privateKey2, msg2) 60 | sig3 := Sign(privateKey, msg3) 61 | opts := &Options{ 62 | Context: "yippie ki-yay", 63 | Verify: VerifyOptionsFIPS_186_5, 64 | } 65 | sig4, err := privateKey.Sign(nil, msg4, opts) 66 | if err != nil { 67 | panic("SignWithOptions: " + err.Error()) 68 | } 69 | sig5 := Sign(privateKey, msg5) 70 | 71 | // Batch verification 72 | verifier := NewBatchVerifier() 73 | verifier.Add(publicKey, msg1, sig1) 74 | verifier.Add(publicKey2, msg2, sig2) // Public keys can be different. 75 | verifier.Add(publicKey, msg3, sig3) 76 | 77 | // It is possible to specify verification options on a 78 | // per-batch-entry basis, including Ed25519ph/Ed25519ctx. 79 | verifier.AddWithOptions(publicKey, msg4, sig4, opts) 80 | 81 | // Only verify the batch, receiving no information about which 82 | // batch entries are incorrect in the event of a failure. 83 | // 84 | // Note: Verify is probably more useful. 85 | if !verifier.VerifyBatchOnly(rand.Reader) { 86 | panic("verifier.VerifyBatchOnly failed") 87 | } 88 | 89 | // Verify the batch, and return a vector showing the valid entries. 90 | allOk, okVec := verifier.Verify(rand.Reader) 91 | if !allOk { 92 | panic("verifier.Verify failed") 93 | } 94 | for i, v := range okVec { 95 | if !v { 96 | panic(fmt.Sprintf("verifier.Verify: entry %d invalid", i)) 97 | } 98 | } 99 | 100 | // Batch failure 101 | sig5[16] ^= 0xa5 102 | verifier.Add(publicKey, msg5, sig5) 103 | allOk, okVec = verifier.Verify(rand.Reader) 104 | if allOk { 105 | panic("verifier.Verify succeeded when batch should fail") 106 | } 107 | for i, v := range okVec[:4] { 108 | if !v { 109 | panic(fmt.Sprintf("verifier.Verify: entry %d invalid", i)) 110 | } 111 | } 112 | if okVec[4] { 113 | panic("verifier.Verify: entry 4 valid") 114 | } 115 | 116 | fmt.Println("ok") 117 | // Output: ok 118 | } 119 | -------------------------------------------------------------------------------- /primitives/ed25519/example_options_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package ed25519 31 | 32 | import ( 33 | "crypto/rand" 34 | "fmt" 35 | ) 36 | 37 | // ExampleOptions demonstrates the configurable verification behavior. 38 | func ExampleOptions() { 39 | // As alluded to in the basic example, there are currently many 40 | // definitions of Ed25519 signature verification in the wild. 41 | // 42 | // To navigate this, curve25519-voi provides a "sensible" default, 43 | // and also supporting verification behavior that exactly matches 44 | // other common implementations (within reason). 45 | 46 | msg := []byte("test message") 47 | 48 | publicKey, privateKey, err := GenerateKey(rand.Reader) 49 | if err != nil { 50 | panic("GenerateKey: " + err.Error()) 51 | } 52 | sig := Sign(privateKey, msg) 53 | 54 | // FIPS 186-5 (aka RFC 8032 with cofactored verification) 55 | opts := &Options{ 56 | Verify: VerifyOptionsFIPS_186_5, 57 | } 58 | if !VerifyWithOptions(publicKey, msg, sig, opts) { 59 | panic("VerifyWithOptions(FIPS_186_5): failed") 60 | } 61 | 62 | // ZIP-215 (aka ed25519consensus) 63 | opts = &Options{ 64 | Verify: VerifyOptionsZIP_215, 65 | } 66 | opts.Verify = VerifyOptionsZIP_215 67 | if !VerifyWithOptions(publicKey, msg, sig, opts) { 68 | panic("VerifyWithOptions(default): failed") 69 | } 70 | 71 | // Go standard library (crypto/ed25519) 72 | opts.Verify = VerifyOptionsStdLib 73 | if !VerifyWithOptions(publicKey, msg, sig, opts) { 74 | panic("VerifyWithOptions(StdLib): failed") 75 | } 76 | 77 | fmt.Println("ok") 78 | // Output: ok 79 | } 80 | -------------------------------------------------------------------------------- /primitives/ed25519/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package ed25519 31 | 32 | import ( 33 | "crypto" 34 | "crypto/rand" 35 | "crypto/sha512" 36 | "fmt" 37 | ) 38 | 39 | // Example demonstrates common operations. 40 | func Example() { 41 | // Basic operations are API compatible with crypto/ed25519, as in 42 | // curve25519-voi implements a superset of the crypto/ed25519 API. 43 | 44 | msg := []byte("test message") 45 | 46 | // Key generation 47 | publicKey, privateKey, err := GenerateKey(rand.Reader) 48 | if err != nil { 49 | panic("GenerateKey: " + err.Error()) 50 | } 51 | 52 | // Signing 53 | sig := Sign(privateKey, msg) 54 | 55 | // Verification 56 | if !Verify(publicKey, msg, sig) { 57 | panic("Verify: failed") 58 | } 59 | 60 | // Verification semantics are incompatible with crypto/ed25519 61 | // by default. It is possible to generate signatures that will be 62 | // accepted by one (and rejected by the other), though this will 63 | // NEVER happen during normal operation. 64 | // 65 | // If exact compatibility with the standard library is required 66 | // then VerifyWithOptions must be used with the appropriate options. 67 | // 68 | // Note: Over 99% of the users do not need this, the various edge 69 | // case incompatiblities are systemic across the whole Ed25519 70 | // ecosystem as a whole, and RFC 8032 explicitly allows for this 71 | // situation. 72 | opts := &Options{ 73 | Verify: VerifyOptionsStdLib, 74 | } 75 | if !VerifyWithOptions(publicKey, msg, sig, opts) { 76 | panic("VerifyWithOptions: failed") 77 | } 78 | 79 | // curve25519-voi supports Ed25519ph and Ed25519ctx as defined in 80 | // RFC 8032 in addition to Ed25519pure. 81 | 82 | // Ed25519ctx 83 | // 84 | // Note: Due to Context being defined as a string, a 0-length 85 | // context is not supported, even though it is allowed but 86 | // discouraged by the RFC. 87 | opts = &Options{ 88 | Context: string("test context"), 89 | } 90 | sig, err = privateKey.Sign(nil, msg, opts) 91 | if err != nil { 92 | panic("SignWithOptions(ctx): " + err.Error()) 93 | } 94 | 95 | if !VerifyWithOptions(publicKey, msg, sig, opts) { 96 | panic("VerifyWithOptions(ctx): failed") 97 | } 98 | 99 | // Ed25519ph 100 | prehash := sha512.Sum512(msg) 101 | opts = &Options{ 102 | Hash: crypto.SHA512, 103 | } 104 | if sig, err = privateKey.Sign(nil, prehash[:], opts); err != nil { 105 | panic("SignWithOptions(ph): " + err.Error()) 106 | } 107 | if !VerifyWithOptions(publicKey, prehash[:], sig, opts) { 108 | panic("VerifyWithOptions(ph): failed") 109 | } 110 | 111 | fmt.Println("ok") 112 | // Output: ok 113 | } 114 | -------------------------------------------------------------------------------- /primitives/ed25519/extra/cache/cache.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | // Package cache implements a set of caching wrappers around Ed25519 31 | // signature verification to transparently accelerate repeated verification 32 | // with the same public key(s). 33 | package cache 34 | 35 | import ( 36 | "github.com/oasisprotocol/curve25519-voi/curve" 37 | "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" 38 | ) 39 | 40 | // Cache is an expanded public key cache. 41 | type Cache interface { 42 | // Get returns a public key's corresponding expanded public key iff 43 | // present in the cache, or returns nil. 44 | Get(publicKey *curve.CompressedEdwardsY) *ed25519.ExpandedPublicKey 45 | 46 | // Put adds the expanded public key to the cache. 47 | Put(publicKey *curve.CompressedEdwardsY, expanded *ed25519.ExpandedPublicKey) 48 | } 49 | 50 | // Verifier verifies signatures, storing expanded public keys in a cache 51 | // for reuse by subsequent verification with the same public key. 52 | // 53 | // Note: Unless there are more cache hits than misses, this will likely 54 | // be a net performance loss. Integration should be followed by 55 | // benchmarking. 56 | type Verifier struct { 57 | cache Cache 58 | } 59 | 60 | // Verify repors whether sig is a valid Ed25519 signature by public key. 61 | func (v *Verifier) Verify(publicKey ed25519.PublicKey, message, sig []byte) bool { 62 | return v.VerifyWithOptions(publicKey, message, sig, &ed25519.Options{}) 63 | } 64 | 65 | // VerifyWithOptions reports whether sig is a valid Ed25519 signature by 66 | // publicKey, with extra Options. 67 | func (v *Verifier) VerifyWithOptions(publicKey ed25519.PublicKey, message, sig []byte, opts *ed25519.Options) bool { 68 | expanded, ok := v.upsertPublicKey(publicKey) 69 | if !ok { 70 | return false 71 | } 72 | 73 | return ed25519.VerifyExpandedWithOptions(expanded, message, sig, opts) 74 | } 75 | 76 | // Add will add the signature to the batch verifier. 77 | func (v *Verifier) Add(verifier *ed25519.BatchVerifier, publicKey ed25519.PublicKey, message, sig []byte) { 78 | v.AddWithOptions(verifier, publicKey, message, sig, &ed25519.Options{}) 79 | } 80 | 81 | // AddWithOptions will add the signature to the batch verifier, with 82 | // extra Options. 83 | func (v *Verifier) AddWithOptions(verifier *ed25519.BatchVerifier, publicKey ed25519.PublicKey, message, sig []byte, opts *ed25519.Options) { 84 | // Note: BatchVerifier.AddWithOptions will do the right thing if 85 | // the expanded public key is nil. 86 | expanded, _ := v.upsertPublicKey(publicKey) 87 | verifier.AddExpandedWithOptions(expanded, message, sig, opts) 88 | } 89 | 90 | // AddPublicKey will expand and add the public key to the cache. 91 | func (v *Verifier) AddPublicKey(publicKey ed25519.PublicKey) { 92 | v.upsertPublicKey(publicKey) 93 | } 94 | 95 | func (v *Verifier) upsertPublicKey(publicKey ed25519.PublicKey) (*ed25519.ExpandedPublicKey, bool) { 96 | var ( 97 | compressed curve.CompressedEdwardsY 98 | err error 99 | ) 100 | if _, err = compressed.SetBytes(publicKey); err != nil { 101 | return nil, false 102 | } 103 | 104 | expanded := v.cache.Get(&compressed) 105 | if expanded == nil { 106 | if expanded, err = ed25519.NewExpandedPublicKey(compressed[:]); err != nil { 107 | return nil, false 108 | } 109 | v.cache.Put(&compressed, expanded) 110 | } 111 | 112 | return expanded, true 113 | } 114 | 115 | // NewVerifier creates a new Verifier instance backed by a Cache. 116 | func NewVerifier(cache Cache) *Verifier { 117 | return &Verifier{ 118 | cache: cache, 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /primitives/ed25519/extra/cache/cache_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package cache 31 | 32 | import ( 33 | "testing" 34 | 35 | "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" 36 | ) 37 | 38 | const testCacheSize = 10 39 | 40 | var testMsg = []byte("This is only a test of the emergency broadcast system") 41 | 42 | func BenchmarkCache(b *testing.B) { 43 | b.Run("Verify/Miss", benchCacheMiss) 44 | b.Run("Verify/Hit", benchCacheHit) 45 | } 46 | 47 | func benchCacheMiss(b *testing.B) { 48 | v := NewVerifier(NewLRUCache(testCacheSize)) 49 | 50 | b.ReportAllocs() 51 | 52 | for i := 0; i < b.N; i++ { 53 | b.StopTimer() 54 | pub, priv, err := ed25519.GenerateKey(nil) 55 | if err != nil { 56 | b.Fatalf("failed to generate key: %v", err) 57 | } 58 | sig := ed25519.Sign(priv, testMsg) 59 | b.StartTimer() 60 | 61 | if !v.Verify(pub, testMsg, sig) { 62 | b.Fatalf("failed to verify signature") 63 | } 64 | } 65 | } 66 | 67 | func benchCacheHit(b *testing.B) { 68 | v := NewVerifier(NewLRUCache(testCacheSize)) 69 | 70 | pub, priv, err := ed25519.GenerateKey(nil) 71 | if err != nil { 72 | b.Fatalf("failed to generate key: %v", err) 73 | } 74 | v.AddPublicKey(pub) 75 | sig := ed25519.Sign(priv, testMsg) 76 | 77 | b.ResetTimer() 78 | b.ReportAllocs() 79 | 80 | for i := 0; i < b.N; i++ { 81 | if !v.Verify(pub, testMsg, sig) { 82 | b.Fatalf("failed to verify signature") 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /primitives/ed25519/extra/cache/lru.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package cache 31 | 32 | import ( 33 | "container/list" 34 | "sync" 35 | 36 | "github.com/oasisprotocol/curve25519-voi/curve" 37 | "github.com/oasisprotocol/curve25519-voi/primitives/ed25519" 38 | ) 39 | 40 | type lruCache struct { 41 | sync.Mutex 42 | 43 | store map[curve.CompressedEdwardsY]*lruEntry 44 | list list.List 45 | 46 | capacity int 47 | } 48 | 49 | type lruEntry struct { 50 | publicKey *ed25519.ExpandedPublicKey 51 | element *list.Element 52 | } 53 | 54 | func (cache *lruCache) getLocked(publicKey *curve.CompressedEdwardsY) *ed25519.ExpandedPublicKey { 55 | entry := cache.store[*publicKey] 56 | if entry == nil { 57 | return nil 58 | } 59 | 60 | cache.list.Remove(entry.element) 61 | entry.element = cache.list.PushFront(entry) 62 | 63 | return entry.publicKey 64 | } 65 | 66 | func (cache *lruCache) Get(publicKey *curve.CompressedEdwardsY) *ed25519.ExpandedPublicKey { 67 | cache.Lock() 68 | defer cache.Unlock() 69 | 70 | return cache.getLocked(publicKey) 71 | } 72 | 73 | func (cache *lruCache) Put(publicKey *curve.CompressedEdwardsY, expanded *ed25519.ExpandedPublicKey) { 74 | cache.Lock() 75 | defer cache.Unlock() 76 | 77 | // Do a lookup to see if the entry already exists. 78 | if entry := cache.getLocked(publicKey); entry != nil { 79 | // Already in the cache, and now marked as most-recently-used. 80 | return 81 | } 82 | 83 | entry := &lruEntry{ 84 | publicKey: expanded, 85 | } 86 | 87 | // Evict the Least-Recently-Used entry if any. 88 | if l := cache.list.Len(); l == cache.capacity { 89 | element := cache.list.Back() 90 | entryValue := cache.list.Remove(element) 91 | 92 | entry := entryValue.(*lruEntry) 93 | delete(cache.store, entry.publicKey.CompressedY()) 94 | } 95 | 96 | cache.store[*publicKey] = entry 97 | entry.element = cache.list.PushFront(entry) 98 | } 99 | 100 | // NewLRUCache creates a new cache with a Least-Recently-Used replacement 101 | // policy. Cache instances returned are thread-safe. 102 | func NewLRUCache(capacity int) Cache { 103 | if capacity <= 0 { 104 | panic("edcache: capacity must be < 0") 105 | } 106 | 107 | return &lruCache{ 108 | store: make(map[curve.CompressedEdwardsY]*lruEntry), 109 | capacity: capacity, 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /primitives/ed25519/testdata/ed25519vectors.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/ed25519/testdata/ed25519vectors.json.gz -------------------------------------------------------------------------------- /primitives/ed25519/testdata/eddsa_test.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/ed25519/testdata/eddsa_test.json.gz -------------------------------------------------------------------------------- /primitives/ed25519/testdata/rfc8032_ctx.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/ed25519/testdata/rfc8032_ctx.json.gz -------------------------------------------------------------------------------- /primitives/ed25519/testdata/sign.input.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/ed25519/testdata/sign.input.gz -------------------------------------------------------------------------------- /primitives/ed25519/testdata/speccheck_cases.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/ed25519/testdata/speccheck_cases.json.gz -------------------------------------------------------------------------------- /primitives/ed25519/testdata/zip215.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/ed25519/testdata/zip215.json.gz -------------------------------------------------------------------------------- /primitives/ed25519/zip215_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package ed25519 31 | 32 | import ( 33 | "compress/gzip" 34 | "crypto/rand" 35 | "encoding/json" 36 | "fmt" 37 | "os" 38 | "testing" 39 | 40 | "github.com/oasisprotocol/curve25519-voi/internal/testhelpers" 41 | ) 42 | 43 | type zip215TestVector [2]string 44 | 45 | func (tc zip215TestVector) Run(t *testing.T, isBatch, isZIP215 bool) { 46 | msg := []byte("Zcash") 47 | rawPk := testhelpers.MustUnhex(t, tc[0]) 48 | sig := testhelpers.MustUnhex(t, tc[1]) 49 | 50 | pk := PublicKey(rawPk) 51 | var opts Options 52 | switch isZIP215 { 53 | case true: 54 | opts.Verify = VerifyOptionsZIP_215 55 | case false: 56 | opts.Verify = VerifyOptionsDefault 57 | } 58 | 59 | var sigOk bool 60 | switch isBatch { 61 | case false: 62 | sigOk = VerifyWithOptions(pk, msg, sig, &opts) 63 | case true: 64 | v := NewBatchVerifier() 65 | 66 | for i := 0; i < testBatchSize; i++ { 67 | v.AddWithOptions(pk, msg, sig, &opts) 68 | } 69 | 70 | var valid []bool 71 | sigOk, valid = v.Verify(rand.Reader) 72 | for i, v := range valid { 73 | if v != sigOk { 74 | t.Fatalf("sigOk != valid[%d]", i) 75 | } 76 | } 77 | } 78 | 79 | // The ZIP-215 test vectors are cases that a ZIP-215 verifier should 80 | // pass, and the default verification algorithm should reject. 81 | if sigOk != isZIP215 { 82 | t.Fatalf("failed to verify signature") 83 | } 84 | } 85 | 86 | func TestZIP215(t *testing.T) { 87 | f, err := os.Open("testdata/zip215.json.gz") 88 | if err != nil { 89 | t.Fatal(err) 90 | } 91 | defer f.Close() 92 | rd, err := gzip.NewReader(f) 93 | if err != nil { 94 | t.Fatal(err) 95 | } 96 | defer rd.Close() 97 | 98 | var testVectors []zip215TestVector 99 | dec := json.NewDecoder(rd) 100 | if err = dec.Decode(&testVectors); err != nil { 101 | t.Fatal(err) 102 | } 103 | 104 | for idx, tc := range testVectors { 105 | n := fmt.Sprintf("TestCase_%d", idx) 106 | t.Run(n, func(t *testing.T) { 107 | tc.Run(t, false, false) 108 | }) 109 | t.Run(n+"_Batch", func(t *testing.T) { 110 | tc.Run(t, true, false) 111 | }) 112 | 113 | n = n + "_ZIP215" 114 | t.Run(n, func(t *testing.T) { 115 | tc.Run(t, false, true) 116 | }) 117 | t.Run(n+"_Batch", func(t *testing.T) { 118 | tc.Run(t, true, true) 119 | }) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /primitives/h2c/testdata/edwards25519_XMD_SHA-512_ELL2_NU_.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/edwards25519_XMD_SHA-512_ELL2_NU_.json.gz -------------------------------------------------------------------------------- /primitives/h2c/testdata/edwards25519_XMD_SHA-512_ELL2_RO_.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/edwards25519_XMD_SHA-512_ELL2_RO_.json.gz -------------------------------------------------------------------------------- /primitives/h2c/testdata/expand_message_xmd_SHA256_256.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/expand_message_xmd_SHA256_256.json.gz -------------------------------------------------------------------------------- /primitives/h2c/testdata/expand_message_xmd_SHA256_38.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/expand_message_xmd_SHA256_38.json.gz -------------------------------------------------------------------------------- /primitives/h2c/testdata/expand_message_xmd_SHA512_38.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/expand_message_xmd_SHA512_38.json.gz -------------------------------------------------------------------------------- /primitives/h2c/testdata/expand_message_xof_SHAKE128_256.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/expand_message_xof_SHAKE128_256.json.gz -------------------------------------------------------------------------------- /primitives/h2c/testdata/expand_message_xof_SHAKE128_36.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/expand_message_xof_SHAKE128_36.json.gz -------------------------------------------------------------------------------- /primitives/h2c/testdata/expand_message_xof_SHAKE256_36.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/h2c/testdata/expand_message_xof_SHAKE256_36.json.gz -------------------------------------------------------------------------------- /primitives/sr25519/doc.go: -------------------------------------------------------------------------------- 1 | // Package sr25519 implements the sr25519 signature algorithm. See 2 | // https://github.com/w3f/schnorrkel/. 3 | package sr25519 4 | 5 | import _ "github.com/oasisprotocol/curve25519-voi/internal/toolchain" 6 | -------------------------------------------------------------------------------- /primitives/sr25519/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package sr25519 31 | 32 | import ( 33 | "crypto/rand" 34 | "crypto/sha512" 35 | "fmt" 36 | ) 37 | 38 | // Example demonstrates common operations. 39 | func Example() { 40 | // Basic operations attempt to be similar to the w3f/schnorrkel 41 | // Rust crate, while being as close to an idiomatic Go API as 42 | // possible. 43 | 44 | // Key generation 45 | 46 | miniSecretKey, err := GenerateMiniSecretKey(rand.Reader) 47 | if err != nil { 48 | panic("GenerateMiniSecretKey: " + err.Error()) 49 | } 50 | 51 | secretKey := miniSecretKey.ExpandUniform() // ExpandEd25519 is also supported 52 | keypair := secretKey.KeyPair() // The KeyPair type is what is used for signing. 53 | publicKey := keypair.PublicKey() 54 | 55 | // Serialization 56 | 57 | publicBytes, err := publicKey.MarshalBinary() 58 | if err != nil { 59 | panic("publicKey.MarshalBinary: " + err.Error()) 60 | } 61 | 62 | var publicKey2 PublicKey 63 | if err = publicKey2.UnmarshalBinary(publicBytes); err != nil { 64 | panic("publicKey.UnmarshalBinary: " + err.Error()) 65 | } 66 | if !publicKey.Equal(&publicKey2) { 67 | panic("public key did not round trip with BinaryMarshaller") 68 | } 69 | 70 | publicKey3, err := NewPublicKeyFromBytes(publicBytes) 71 | if err != nil { 72 | panic("NewPublicKeyFromBytes: " + err.Error()) 73 | } 74 | if !publicKey.Equal(publicKey3) { 75 | panic("public key did not round trip with NewPublicKeyFromBytes") 76 | } 77 | 78 | // Signing 79 | signingContext := NewSigningContext([]byte("example signing context")) 80 | msg := []byte("test message") 81 | 82 | transcript := signingContext.NewTranscriptBytes(msg) 83 | signature, err := keypair.Sign(rand.Reader, transcript) 84 | if err != nil { 85 | panic("Sign: " + err.Error()) 86 | } 87 | 88 | h := sha512.New512_256() 89 | _, _ = h.Write(msg) 90 | transcriptHashed := signingContext.NewTranscriptHash(h) 91 | signatureHashed, err := keypair.Sign(rand.Reader, transcriptHashed) 92 | if err != nil { 93 | panic("Sign(hashed): " + err.Error()) 94 | } 95 | 96 | signatureBytes, err := signature.MarshalBinary() 97 | if err != nil { 98 | panic("signature.MarshalBinary: " + err.Error()) 99 | } 100 | 101 | signature2, err := NewSignatureFromBytes(signatureBytes) 102 | if err != nil { 103 | panic("NewSignatureFromBytes: " + err.Error()) 104 | } 105 | 106 | // Verification 107 | // 108 | // Note: Unlike the "other" Go sr25519 library, signing and verification 109 | // are side-effect free, and do not alter the transcript, so the transcripts 110 | // from the signing example are reused for brevity. 111 | 112 | if !publicKey.Verify(transcript, signature) { 113 | panic("Verify failed") 114 | } 115 | if !publicKey.Verify(transcript, signature2) { 116 | panic("Verify(signature2) failed, round-trip failure?") 117 | } 118 | 119 | if !publicKey.Verify(transcriptHashed, signatureHashed) { 120 | panic("Verify(hashed) failed") 121 | } 122 | 123 | // This would include a (separate) batch-verification example, but the 124 | // API is essentially identical to Ed25519, except based around transcripts. 125 | 126 | fmt.Println("ok") 127 | // Output: ok 128 | } 129 | -------------------------------------------------------------------------------- /primitives/x25519/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package x25519 31 | 32 | import ( 33 | "bytes" 34 | "crypto/rand" 35 | "fmt" 36 | ) 37 | 38 | // Example demonstrates common operations. 39 | func Example() { 40 | // Basic operations are API compatible with x/crypto/curve25519. 41 | 42 | // Key generation 43 | alicePrivate := make([]byte, ScalarSize) 44 | if _, err := rand.Read(alicePrivate); err != nil { 45 | panic("rand.Read: " + err.Error()) 46 | } 47 | 48 | alicePublic, err := X25519(alicePrivate, Basepoint) 49 | if err != nil { 50 | panic("x25519.X25519(Basepoint): " + err.Error()) 51 | } 52 | 53 | var bobPrivate, bobPublic [32]byte 54 | if _, err := rand.Read(bobPrivate[:]); err != nil { 55 | panic("rand.Read: " + err.Error()) 56 | } 57 | ScalarBaseMult(&bobPublic, &bobPrivate) 58 | 59 | // Shared secret 60 | // 61 | // Note: If the "all zero output" check for contributory behavior 62 | // is not wanted, then the "deprecated" ScalarMult call should be 63 | // used. Marking a routine that still has useful behavior as 64 | // deprecated isn't great, but that is what x/crypto/curve25519 does. 65 | aliceShared, err := X25519(alicePrivate, bobPublic[:]) 66 | if err != nil { 67 | panic("x25519.X25519: " + err.Error()) 68 | } 69 | 70 | var bobShared, tmp [32]byte 71 | copy(tmp[:], alicePublic) 72 | ScalarMult(&bobShared, &bobPrivate, &tmp) //nolint: staticcheck 73 | 74 | if !bytes.Equal(aliceShared, bobShared[:]) { 75 | panic("shared secret mismatch") 76 | } 77 | 78 | fmt.Println("ok") 79 | // Output: ok 80 | } 81 | -------------------------------------------------------------------------------- /primitives/x25519/testdata/x25519_test.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oasisprotocol/curve25519-voi/1f23a7beb09a352354cbd7277c6b7f0170cf6d5d/primitives/x25519/testdata/x25519_test.json.gz -------------------------------------------------------------------------------- /primitives/x25519/wycheproof_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Oasis Labs Inc. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 10 | // 2. Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // 14 | // 3. Neither the name of the copyright holder nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 19 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 21 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 24 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 25 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | package x25519 31 | 32 | import ( 33 | "bytes" 34 | "compress/gzip" 35 | "encoding/json" 36 | "fmt" 37 | "os" 38 | "testing" 39 | 40 | "github.com/oasisprotocol/curve25519-voi/internal/testhelpers" 41 | ) 42 | 43 | type wycheproofXDHFlags int 44 | 45 | const ( 46 | flagLowOrderPublic wycheproofXDHFlags = iota 47 | flagNonCanonicalPublic 48 | flagSmallPublicKey 49 | flagTwist 50 | flagZeroSharedSecret 51 | ) 52 | 53 | type wycheproofTestVectors struct { 54 | Algorithm string `json:"algorithm"` 55 | Version string `json:"generatorVersion"` 56 | NumTests int `json:"numberOfTests"` 57 | TestGroups []wycheproofTestGroup `json:"TestGroups"` 58 | } 59 | 60 | type wycheproofTestGroup struct { 61 | Curve string `json:"string"` 62 | Type string `json:"type"` 63 | Tests []wycheproofTestCase `json:"tests"` 64 | } 65 | 66 | type wycheproofTestCase struct { 67 | ID int `json:"tcId"` 68 | Comment string `json:"comment"` 69 | Public string `json:"public"` 70 | Private string `json:"private"` 71 | Shared string `json:"shared"` 72 | Result string `json:"result"` 73 | Flags []string `json:"flags"` 74 | } 75 | 76 | func (tc *wycheproofTestCase) Run(t *testing.T) { 77 | if tc.Comment != "" { 78 | t.Logf("%s", tc.Comment) 79 | } 80 | 81 | publicKey := testhelpers.MustUnhex(t, tc.Public) 82 | privateKey := testhelpers.MustUnhex(t, tc.Private) 83 | sharedKey := testhelpers.MustUnhex(t, tc.Shared) 84 | 85 | flags := make(map[wycheproofXDHFlags]bool) 86 | for _, s := range tc.Flags { 87 | switch s { 88 | case "LowOrderPublic": 89 | flags[flagLowOrderPublic] = true 90 | case "NonCanonicalPublic": 91 | flags[flagNonCanonicalPublic] = true 92 | case "SmallPublicKey": 93 | flags[flagSmallPublicKey] = true 94 | case "Twist": 95 | flags[flagTwist] = true 96 | case "ZeroSharedSecret": 97 | flags[flagZeroSharedSecret] = true 98 | } 99 | } 100 | 101 | // First test the raw "Deprecated" ScalarMult routine. 102 | var dst, in, base [32]byte 103 | copy(in[:], privateKey) 104 | copy(base[:], publicKey) 105 | ScalarMult(&dst, &in, &base) 106 | 107 | if !bytes.Equal(dst[:], sharedKey) { 108 | t.Fatalf("failed ScalarMult(dst, priv, pub): %x (expected %x)", dst[:], sharedKey) 109 | } 110 | 111 | // The "new" X25519 routine enforces contributory behavior, with an 112 | // error message that appears as if it is rejecting low order public 113 | // keys. The check is for an all zero shared secret, so use that flag 114 | // though both are excluseively set as a pair. 115 | shouldFail := flags[flagZeroSharedSecret] 116 | 117 | out, err := X25519(privateKey, publicKey) 118 | switch shouldFail { 119 | case true: 120 | if err == nil { 121 | t.Fatalf("X25519(priv, pub) returned no error when it should fail") 122 | } 123 | case false: 124 | if err != nil { 125 | t.Fatalf("failed X25519(priv, pub): %v", err) 126 | } 127 | if !bytes.Equal(out, sharedKey) { 128 | t.Fatalf("failed X25519(priv, pub): %x (expected %x)", out, sharedKey) 129 | } 130 | } 131 | } 132 | 133 | func TestWycheproof(t *testing.T) { 134 | f, err := os.Open("testdata/x25519_test.json.gz") 135 | if err != nil { 136 | t.Fatal(err) 137 | } 138 | defer f.Close() 139 | rd, err := gzip.NewReader(f) 140 | if err != nil { 141 | t.Fatal(err) 142 | } 143 | defer rd.Close() 144 | 145 | var testVectors wycheproofTestVectors 146 | 147 | dec := json.NewDecoder(rd) 148 | if err = dec.Decode(&testVectors); err != nil { 149 | t.Fatal(err) 150 | } 151 | 152 | t.Logf("Wycheproof Version: %s", testVectors.Version) 153 | 154 | var numTests int 155 | for _, group := range testVectors.TestGroups { 156 | for _, testCase := range group.Tests { 157 | n := fmt.Sprintf("TestCase/%d", testCase.ID) 158 | t.Run(n, func(t *testing.T) { 159 | testCase.Run(t) 160 | }) 161 | numTests++ 162 | } 163 | } 164 | if numTests != testVectors.NumTests { 165 | t.Errorf("unexpected number of tests ran: %d (expected %d)", numTests, testVectors.NumTests) 166 | } 167 | } 168 | --------------------------------------------------------------------------------