diff --git a/.github/workflows/build-aarch64.yml b/.github/workflows/build-aarch64.yml index 3f007a04d..25bbdf2d2 100644 --- a/.github/workflows/build-aarch64.yml +++ b/.github/workflows/build-aarch64.yml @@ -2,6 +2,11 @@ name: Build ARM64 wheel on: [push, pull_request] +concurrency: + # SHA is added to the end if on `main` to let all main workflows run + group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ (github.ref == 'refs/heads/main') && github.sha || '' }} + cancel-in-progress: true + jobs: build_wheels: name: Build wheel on ${{ matrix.os }} @@ -19,7 +24,7 @@ jobs: access_token: ${{ github.token }} - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/.github/workflows/build-m1-wheel.yml b/.github/workflows/build-m1-wheel.yml index 34acf2131..049a38bd2 100644 --- a/.github/workflows/build-m1-wheel.yml +++ b/.github/workflows/build-m1-wheel.yml @@ -2,6 +2,11 @@ name: Build M1 Wheels on: [push, pull_request] +concurrency: + # SHA is added to the end if on `main` to let all main workflows run + group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ (github.ref == 'refs/heads/main') && github.sha || '' }} + cancel-in-progress: true + jobs: build_wheels: name: Build wheel on Mac M1 @@ -17,7 +22,7 @@ jobs: access_token: ${{ github.token }} - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index 86f5e0ce8..fd4aa5909 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -2,6 +2,11 @@ name: Build and Test C++, Javascript, and Python on: [push, pull_request] +concurrency: + # SHA is added to the end if on `main` to let all main workflows run + group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ (github.ref == 'refs/heads/main') && github.sha || '' }} + cancel-in-progress: true + jobs: build_wheels: name: Build and Test on ${{ matrix.os }} CPython ${{ matrix.python }} @@ -20,7 +25,7 @@ jobs: access_token: ${{ github.token }} - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - uses: actions/setup-python@v2 name: Install Python @@ -62,7 +67,7 @@ jobs: python python-impl/impl-test.py - name: Install emsdk - uses: mymindstorm/setup-emsdk@v9 + uses: mymindstorm/setup-emsdk@v11 - name: Test javascript bindings run: | diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index ef38eebfc..0c620ce49 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -9,7 +9,99 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-latest, ubuntu-latest, windows-latest] + os: + - name: macOS + matrix: macos + runs-on: + arm: [macOS, ARM64] + intel: [macos-latest] + cibw-archs-macos: + arm: arm64 + intel: x86_64 + - name: Ubuntu + matrix: ubuntu + runs-on: + arm: [Linux, ARM64] + intel: [ubuntu-latest] + - name: Windows + matrix: windows + runs-on: + intel: [windows-latest] + python: + - major-dot-minor: '3.7' + cibw-build: 'cp37-*' + manylinux: + arch: manylinux2014 + intel: manylinux2010 + matrix: '3.7' + - major-dot-minor: '3.8' + cibw-build: 'cp38-*' + manylinux: + arch: manylinux2014 + intel: manylinux2010 + matrix: '3.8' + - major-dot-minor: '3.9' + cibw-build: 'cp39-*' + manylinux: + arch: manylinux2014 + intel: manylinux2010 + matrix: '3.9' + - major-dot-minor: '3.10' + cibw-build: 'cp310-*' + manylinux: + arch: manylinux2014 + intel: manylinux2010 + matrix: '3.10' + - major-dot-minor: '3.11' + cibw-build: 'cp311-*' + manylinux: + arch: manylinux2014 + intel: manylinux2014 + matrix: '3.11' + arch: + - name: ARM + matrix: arm + - name: Intel + matrix: intel + exclude: + # Only partial entries are required here by GitHub Actions so generally I + # only specify the `matrix:` entry. The super linter complains so for now + # all entries are included to avoid that. Reported at + # https://github.com/github/super-linter/issues/3016 + - os: + name: Windows + matrix: windows + runs-on: + intel: [windows-latest] + arch: + name: ARM + matrix: arm + - os: + name: macOS + matrix: macos + runs-on: + arm: [macOS, ARM64] + intel: [macos-latest] + python: + major-dot-minor: '3.7' + cibw-build: 'cp37-*' + matrix: '3.7' + arch: + name: ARM + matrix: arm + - os: + name: macOS + matrix: macos + runs-on: + arm: [macOS, ARM64] + intel: [macos-latest] + python: + major-dot-minor: '3.8' + cibw-build: 'cp38-*' + matrix: '3.8' + arch: + name: ARM + matrix: arm steps: - name: Cancel previous runs on the same branch @@ -50,6 +142,7 @@ jobs: with: output-dir: dist env: + CIBW_PRERELEASE_PYTHONS: True CIBW_BUILD_VERBOSITY_MACOS: 0 CIBW_BUILD_VERBOSITY_LINUX: 0 CIBW_BUILD_VERBOSITY_WINDOWS: 0 diff --git a/.github/workflows/js-bindings.yml b/.github/workflows/js-bindings.yml new file mode 100644 index 000000000..887c8df3d --- /dev/null +++ b/.github/workflows/js-bindings.yml @@ -0,0 +1,60 @@ +name: Build & Publish JS Bindings + +on: + push: + branches: + - main + tags: + - '**' + pull_request: + branches: + - '**' + +concurrency: + # SHA is added to the end if on `main` to let all main workflows run + group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ (github.ref == 'refs/heads/main') && github.sha || '' }} + cancel-in-progress: true + +jobs: + js_bindings: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Install emsdk + uses: mymindstorm/setup-emsdk@v11 + + - name: Get the version + id: version_info + run: echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/} + + - name: Update version in package.json + if: startsWith(github.ref, 'refs/tags/') + working-directory: ${{ github.workspace }}/js-bindings + env: + SOURCE_TAG: ${{ steps.version_info.outputs.SOURCE_TAG }} + run: | + jq --arg VER "$SOURCE_TAG" '.version=$VER' package.json > temp.json && mv temp.json package.json + + - name: Build JS + run: ./js_build.sh + + - name: Publish + if: startsWith(github.ref, 'refs/tags/') + working-directory: ${{ github.workspace }}/js_build/js-bindings + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: | + echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc + npm publish --access public + + - name: Cleanup + if: always() + run: + rm ${{ github.workspace }}/js_build/js-bindings/.npmrc || true diff --git a/.github/workflows/relic-nightly.yml b/.github/workflows/relic-nightly.yml index c75972d31..380fc2b60 100644 --- a/.github/workflows/relic-nightly.yml +++ b/.github/workflows/relic-nightly.yml @@ -5,6 +5,11 @@ on: - cron: "0 11 * * *" workflow_dispatch: +concurrency: + # SHA is added to the end if on `main` to let all main workflows run + group: ${{ github.ref }}-${{ github.workflow }}-${{ github.event_name }}-${{ (github.ref == 'refs/heads/main') && github.sha || '' }} + cancel-in-progress: true + jobs: build_wheels: name: Build and Test with Relic Nightly @@ -22,7 +27,7 @@ jobs: access_token: ${{ github.token }} - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Ubuntu build C++ and test Relic at origin/main if: startsWith(matrix.os, 'ubuntu') @@ -69,7 +74,7 @@ jobs: python python-impl/impl-test.py - name: Install emsdk - uses: mymindstorm/setup-emsdk@v9 + uses: mymindstorm/setup-emsdk@v11 - name: Test javascript bindings run: | diff --git a/README.md b/README.md index aa8828005..26f854aa2 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ vector message = {1, 2, 3, 4, 5}; // Message is passed in as a byte ve G2Element signature = AugSchemeMPL().Sign(sk, message); // Verify the signature -bool ok = AugSchemeMPL().Verify(pk, message, signature)); +bool ok = AugSchemeMPL().Verify(pk, message, signature); ``` ## Serializing keys and signatures to bytes diff --git a/python-bindings/pythonbindings.cpp b/python-bindings/pythonbindings.cpp index db2757d38..f85a3658d 100644 --- a/python-bindings/pythonbindings.cpp +++ b/python-bindings/pythonbindings.cpp @@ -584,6 +584,24 @@ PYBIND11_MODULE(blspy, m) auto data_ptr = reinterpret_cast(info.ptr); return GTElement::FromBytes(Bytes(data_ptr, GTElement::SIZE)); }) + .def( + "from_bytes_unchecked", + [](py::buffer const b) { + py::buffer_info info = b.request(); + if (info.format != py::format_descriptor::format() || + info.ndim != 1) + throw std::runtime_error("Incompatible buffer format!"); + + if ((int)info.size != GTElement::SIZE) { + throw std::invalid_argument( + "Length of bytes object not equal to GTElement::SIZE"); + } + auto data_ptr = reinterpret_cast(info.ptr); + std::array data; + std::copy(data_ptr, data_ptr + GTElement::SIZE, data.data()); + py::gil_scoped_release release; + return GTElement::FromBytesUnchecked(data); + }) .def("unity", >Element::Unity) .def(py::self == py::self) .def(py::self != py::self) diff --git a/python-impl/ec.py b/python-impl/ec.py index 73ad91741..36f573d11 100644 --- a/python-impl/ec.py +++ b/python-impl/ec.py @@ -238,6 +238,7 @@ def sign_Fq2(element, ec=default_ec_twist) -> bool: def point_to_bytes(point_j: JacobianPoint, ec, FE) -> bytes: + # Zcash serialization described in https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/ point = point_j.to_affine() output = bytearray(bytes(point.x)) @@ -259,7 +260,7 @@ def point_to_bytes(point_j: JacobianPoint, ec, FE) -> bytes: def bytes_to_point(buffer: bytes, ec, FE) -> JacobianPoint: - # Zcash serialization described in https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/ + # Zcash deserialization described in https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/ if FE == Fq: if len(buffer) != 48: @@ -275,9 +276,9 @@ def bytes_to_point(buffer: bytes, ec, FE) -> JacobianPoint: if m_byte in [0x20, 0x60, 0xE0]: raise ValueError("Invalid first three bits") - C_bit = m_byte & 0x80 # First bit - I_bit = m_byte & 0x40 # Second bit - S_bit = m_byte & 0x20 # Third bit + C_bit = (m_byte & 0x80) >> 7 # First bit + I_bit = (m_byte & 0x40) >> 6 # Second bit + S_bit = (m_byte & 0x20) >> 5 # Third bit if C_bit == 0: raise ValueError("First bit must be 1 (only compressed points)") diff --git a/src/elements.cpp b/src/elements.cpp index 503b59c1e..4a4990c39 100644 --- a/src/elements.cpp +++ b/src/elements.cpp @@ -101,7 +101,7 @@ G1Element G1Element::FromMessage(const std::vector& message, return FromMessage(Bytes(message), dst, dst_len); } -G1Element G1Element::FromMessage(const Bytes& message, +G1Element G1Element::FromMessage(Bytes const message, const uint8_t* dst, int dst_len) { @@ -307,7 +307,7 @@ G2Element G2Element::FromMessage(const std::vector& message, return FromMessage(Bytes(message), dst, dst_len, fLegacy); } -G2Element G2Element::FromMessage(const Bytes& message, +G2Element G2Element::FromMessage(Bytes const message, const uint8_t* dst, int dst_len, const bool fLegacy) @@ -440,15 +440,21 @@ G2Element operator*(const bn_t& k, const G2Element& a) { return a * k; } const size_t GTElement::SIZE; -GTElement GTElement::FromBytes(const Bytes& bytes) +GTElement GTElement::FromBytes(Bytes const bytes) +{ + GTElement ele = GTElement::FromBytesUnchecked(bytes); + if (gt_is_valid(*(gt_t*)&ele) == 0) + throw std::invalid_argument("GTElement is invalid"); + return ele; +} + +GTElement GTElement::FromBytesUnchecked(Bytes const bytes) { if (bytes.size() != SIZE) { throw std::invalid_argument("GTElement::FromBytes: Invalid size"); } GTElement ele = GTElement(); gt_read_bin(ele.r, bytes.begin(), GTElement::SIZE); - if (gt_is_valid(*(gt_t*)&ele) == 0) - throw std::invalid_argument("GTElement is invalid"); BLS::CheckRelicErrors(); return ele; } diff --git a/src/elements.hpp b/src/elements.hpp index 320b17363..9bab3ca68 100644 --- a/src/elements.hpp +++ b/src/elements.hpp @@ -46,7 +46,7 @@ class G1Element { static G1Element FromMessage(const std::vector &message, const uint8_t *dst, int dst_len); - static G1Element FromMessage(const Bytes& message, + static G1Element FromMessage(Bytes message, const uint8_t* dst, int dst_len); static G1Element Generator(); @@ -87,7 +87,7 @@ class G2Element { const uint8_t* dst, int dst_len, bool fLegacy = false); - static G2Element FromMessage(const Bytes& message, + static G2Element FromMessage(Bytes message, const uint8_t* dst, int dst_len, bool fLegacy = false); @@ -115,7 +115,8 @@ class G2Element { class GTElement { public: static const size_t SIZE = 384; - static GTElement FromBytes(const Bytes& bytes); + static GTElement FromBytes(Bytes bytes); + static GTElement FromBytesUnchecked(Bytes bytes); static GTElement FromByteVector(const std::vector &bytevec); static GTElement FromNative(const gt_t *element); static GTElement Unity(); // unity