Merge pull request #5506 from UdjinM6/backport_19.3_candidates

[v19.x] Backport 19.3 candidates, v19.3.0 release notes and version bump
This commit is contained in:
PastaPastaPasta 2023-07-27 09:23:38 -05:00 committed by GitHub
commit a884f0c536
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 6442 additions and 204 deletions

View File

@ -1,6 +1,6 @@
AC_PREREQ([2.69])
define(_CLIENT_VERSION_MAJOR, 19)
define(_CLIENT_VERSION_MINOR, 2)
define(_CLIENT_VERSION_MINOR, 3)
define(_CLIENT_VERSION_BUILD, 0)
define(_CLIENT_VERSION_RC, 0)
define(_CLIENT_VERSION_IS_RELEASE, true)

View File

@ -1,4 +1,4 @@
# Dash Core version v19.2.0
# Dash Core version v19.3.0
Release is now available from:
@ -7,8 +7,7 @@ Release is now available from:
This is a new minor version release, bringing various bugfixes and other
improvements.
This release is mandatory for all nodes. This release resolves issues around the
v19 Hard Fork activation. All nodes must upgrade to continue syncing properly.
This release is optional for all nodes.
Please report bugs using the issue tracker at GitHub:
@ -27,15 +26,6 @@ using version < 0.13 you will have to reindex (start with -reindex-chainstate
or -reindex) to make sure your wallet has all the new data synced. Upgrading
from version 0.13 should not require any additional actions.
At the first startup Dash Core will run a migration process which can take
anywhere from a few minutes to thirty minutes to finish. After the migration,
a downgrade to an older version is only possible with a reindex.
Please note that seamless migration is only possible on nodes which did not
reach the v19 fork block. Nodes that reached it can either rewind a couple
of blocks back to a pre-v19 block using `invalidateblock` RPC while still
running the old version or they can reindex instead.
## Downgrade warning
### Downgrade to a version < v19.2.0
@ -46,79 +36,47 @@ reindex or re-sync the whole chain.
# Notable changes
## Resolve v19 Hard Fork Issues
## CoinJoin improvements
One of the goals for the v19 Hard Fork was to activate basic BLS scheme and
start using it in various on-chain and p2p messages. The motivation behind this
change is the need to be aligned with IETF standards. Unfortunately, a few edge
cases were missed in our functional tests and were not caught on testnet either.
v19 activation attempt on mainnet hit one of these edge cases and mainnet
stopped producing blocks. As an intermediate solution v19.1.0 was released which
delayed the start of the signaling for the v19 Hard Fork until June 14th.
This release fixes a couple of issues with mixing on nodes that start with no
wallet loaded initially.
To resolve these issues we had to rework the way BLS public keys are handled
including the way they are serialized in the internal database. This made it
incompatible with older versions of Dash Core, so a db migration path was
implemented for all recent versions.
## Wallet GUI improvements
## Improve migration and historical data support on light clients
Wallets with 100k+ txes should now be able to rescan without hanging forever
while processing notifications for every tx. Running `keypoolrefill` with a
large number of keys will no longer lockup the GUI and can be interrupted.
Running `upgradetohd` can also be interrupted now.
As a side-effect, the solution implemented to resolve v19 Hard Fork issues
opened a path to simplify v19 migration for mobile wallets.
## Changes in RPCs, commands and config options
With previous implementation mobile wallets would have to convert 4k+ pubkeys
at the v19 fork point and that can easily take 10-15 seconds if not more.
Also, after the v19 Hard Fork, if a masternode list is requested from a block
before the v19 Hard Fork, the operator keys were coming in basic BLS scheme,
but the masternode merkleroot hash stored in coinbase transaction at that time
was calculated with legacy BLS scheme. Hence it was impossible to verify the
merkleroot hash.
To fix these issues a new field `nVersion` was introduced for every entry in
`mnlistdiff` p2p message. This field indicates which BLS scheme should be used
when deserialising the message - legacy or basic. `nVersion` of the `mnlistdiff`
message itself will no longer indicate the scheme and must always be set to `1`.
## Improve mixing support on light clients
Recent changes to `dsq` and `dstx` messages allowed mobile clients that get
masternode lists from `mnlistdiff` message to determine the masternode related
to these messages because the `proTxHash` was used instead of the
`masternodeOutpoint`. Once the v19 Hard Fork activates the signature of `dsq`
and `dstx` messages will be based on the `proTxHash` which should make it
possible for mobile clients to verify it.
## Allow keeping Chainlocks enabled without signing new ones
Before this version Chainlocks were either enabled or disabled. Starting with
this version it's possible to set `SPORK_19_CHAINLOCKS_ENABLED` to a non-zero
value to disable the signing of new Chainlocks while still enforcing the best
known one.
- `wipewallettxes`: New RPC command which removes all wallet transactions
- `wipetxes`: New command for `dash-wallet` that removes all wallet transactions
- `masternodelist`: New mode `hpmn` filters only HPMNs/EvoNodes
- `protx list`: New type `hpmn` filters only HPMNs/EvoNodes
- `-blockversion` config option is allowed on non-mainnet networks now
## Other changes
There were a few other minor changes too, specifically:
- reindex on DB corruption should now start properly in Qt
- a mnemonic passphrase longer than 256 symbols no longer crashes the wallet
- a Qt node running with `-disablewawllet` flag should not crash in Settings now
- `-masternodeblsprivkey` and `-sporkkey` values are no longer printed in
`debug.log`
- should use less memory in the long run comparing to older versions
- gmp library detection should work better on macos
- fixed a couple of typos
- Added Kittywhiskers Van Gogh (kittywhiskers) and Odysseas Gabrielides
(ogabrielides) to contributors list in 19.2.0 release notes
- There should be no false "unknown rules activated" warning in GUI and RPCs now
- Empty `settings.json` file no longer results in node startup failure
- Block processing was slightly optimized
- BLS library was updated to version 1.3.0 to fix a couple tiny issues
- Fixed a couple of small issues in tests
# v19.2.0 Change log
# v19.3.0 Change log
See detailed [set of changes](https://github.com/dashpay/dash/compare/v19.1.0...dashpay:v19.2.0).
See detailed [set of changes](https://github.com/dashpay/dash/compare/v19.2.0...dashpay:v19.3.0).
# Credits
Thanks to everyone who directly contributed to this release:
- Konstantin Akimov (knst)
- Nathan Marley (nmarley)
- Odysseas Gabrielides (ogabrielides)
- PastaPastaPasta
- thephez
- UdjinM6
As well as everyone that submitted issues, reviewed pull requests and helped
@ -146,7 +104,8 @@ Dash Core tree 0.12.1.x was a fork of Bitcoin Core tree 0.12.
These release are considered obsolete. Old release notes can be found here:
- [v19.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.0.0.md) released May/22/2023
- [v19.2.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.2.0.md) released June/19/2023
- [v19.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.1.0.md) released May/22/2023
- [v19.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.0.0.md) released Apr/14/2023
- [v18.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.2.md) released Mar/21/2023
- [v18.2.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.1.md) released Jan/17/2023

View File

@ -0,0 +1,189 @@
# Dash Core version v19.2.0
Release is now available from:
<https://www.dash.org/downloads/#wallets>
This is a new minor version release, bringing various bugfixes and other
improvements.
This release is mandatory for all nodes. This release resolves issues around the
v19 Hard Fork activation. All nodes must upgrade to continue syncing properly.
Please report bugs using the issue tracker at GitHub:
<https://github.com/dashpay/dash/issues>
# Upgrading and downgrading
## How to Upgrade
If you are running an older version, shut it down. Wait until it has completely
shut down (which might take a few minutes for older versions), then run the
installer (on Windows) or just copy over /Applications/Dash-Qt (on Mac) or
dashd/dash-qt (on Linux). If you upgrade after DIP0003 activation and you were
using version < 0.13 you will have to reindex (start with -reindex-chainstate
or -reindex) to make sure your wallet has all the new data synced. Upgrading
from version 0.13 should not require any additional actions.
At the first startup Dash Core will run a migration process which can take
anywhere from a few minutes to thirty minutes to finish. After the migration,
a downgrade to an older version is only possible with a reindex.
Please note that seamless migration is only possible on nodes which did not
reach the v19 fork block. Nodes that reached it can either rewind a couple
of blocks back to a pre-v19 block using `invalidateblock` RPC while still
running the old version or they can reindex instead.
## Downgrade warning
### Downgrade to a version < v19.2.0
Downgrading to a version older than v19.2.0 is not supported due to changes
in the evodb database. If you need to use an older version, you must either
reindex or re-sync the whole chain.
# Notable changes
## Resolve v19 Hard Fork Issues
One of the goals for the v19 Hard Fork was to activate basic BLS scheme and
start using it in various on-chain and p2p messages. The motivation behind this
change is the need to be aligned with IETF standards. Unfortunately, a few edge
cases were missed in our functional tests and were not caught on testnet either.
v19 activation attempt on mainnet hit one of these edge cases and mainnet
stopped producing blocks. As an intermediate solution v19.1.0 was released which
delayed the start of the signaling for the v19 Hard Fork until June 14th.
To resolve these issues we had to rework the way BLS public keys are handled
including the way they are serialized in the internal database. This made it
incompatible with older versions of Dash Core, so a db migration path was
implemented for all recent versions.
## Improve migration and historical data support on light clients
As a side-effect, the solution implemented to resolve v19 Hard Fork issues
opened a path to simplify v19 migration for mobile wallets.
With previous implementation mobile wallets would have to convert 4k+ pubkeys
at the v19 fork point and that can easily take 10-15 seconds if not more.
Also, after the v19 Hard Fork, if a masternode list is requested from a block
before the v19 Hard Fork, the operator keys were coming in basic BLS scheme,
but the masternode merkleroot hash stored in coinbase transaction at that time
was calculated with legacy BLS scheme. Hence it was impossible to verify the
merkleroot hash.
To fix these issues a new field `nVersion` was introduced for every entry in
`mnlistdiff` p2p message. This field indicates which BLS scheme should be used
when deserialising the message - legacy or basic. `nVersion` of the `mnlistdiff`
message itself will no longer indicate the scheme and must always be set to `1`.
## Improve mixing support on light clients
Recent changes to `dsq` and `dstx` messages allowed mobile clients that get
masternode lists from `mnlistdiff` message to determine the masternode related
to these messages because the `proTxHash` was used instead of the
`masternodeOutpoint`. Once the v19 Hard Fork activates the signature of `dsq`
and `dstx` messages will be based on the `proTxHash` which should make it
possible for mobile clients to verify it.
## Allow keeping Chainlocks enabled without signing new ones
Before this version Chainlocks were either enabled or disabled. Starting with
this version it's possible to set `SPORK_19_CHAINLOCKS_ENABLED` to a non-zero
value to disable the signing of new Chainlocks while still enforcing the best
known one.
## Other changes
There were a few other minor changes too, specifically:
- reindex on DB corruption should now start properly in Qt
- a mnemonic passphrase longer than 256 symbols no longer crashes the wallet
- a Qt node running with `-disablewawllet` flag should not crash in Settings now
- `-masternodeblsprivkey` and `-sporkkey` values are no longer printed in
`debug.log`
- should use less memory in the long run comparing to older versions
- gmp library detection should work better on macos
- fixed a couple of typos
# v19.2.0 Change log
See detailed [set of changes](https://github.com/dashpay/dash/compare/v19.1.0...dashpay:v19.2.0).
# Credits
Thanks to everyone who directly contributed to this release:
- Kittywhiskers Van Gogh (kittywhiskers)
- Konstantin Akimov (knst)
- Nathan Marley (nmarley)
- Odysseas Gabrielides (ogabrielides)
- PastaPastaPasta
- thephez
- UdjinM6
As well as everyone that submitted issues, reviewed pull requests and helped
debug the release candidates.
# Older releases
Dash was previously known as Darkcoin.
Darkcoin tree 0.8.x was a fork of Litecoin tree 0.8, original name was XCoin
which was first released on Jan/18/2014.
Darkcoin tree 0.9.x was the open source implementation of masternodes based on
the 0.8.x tree and was first released on Mar/13/2014.
Darkcoin tree 0.10.x used to be the closed source implementation of Darksend
which was released open source on Sep/25/2014.
Dash Core tree 0.11.x was a fork of Bitcoin Core tree 0.9,
Darkcoin was rebranded to Dash.
Dash Core tree 0.12.0.x was a fork of Bitcoin Core tree 0.10.
Dash Core tree 0.12.1.x was a fork of Bitcoin Core tree 0.12.
These release are considered obsolete. Old release notes can be found here:
- [v19.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.0.0.md) released May/22/2023
- [v19.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-19.0.0.md) released Apr/14/2023
- [v18.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.2.md) released Mar/21/2023
- [v18.2.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.1.md) released Jan/17/2023
- [v18.2.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.2.0.md) released Jan/01/2023
- [v18.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.1.md) released January/08/2023
- [v18.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.1.0.md) released October/09/2022
- [v18.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.2.md) released October/09/2022
- [v18.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-18.0.1.md) released August/17/2022
- [v0.17.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.3.md) released June/07/2021
- [v0.17.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.17.0.2.md) released May/19/2021
- [v0.16.1.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.1.md) released November/17/2020
- [v0.16.1.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.1.0.md) released November/14/2020
- [v0.16.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.16.0.1.md) released September/30/2020
- [v0.15.0.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.15.0.0.md) released Febrary/18/2020
- [v0.14.0.5](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.5.md) released December/08/2019
- [v0.14.0.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.4.md) released November/22/2019
- [v0.14.0.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.3.md) released August/15/2019
- [v0.14.0.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.2.md) released July/4/2019
- [v0.14.0.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.1.md) released May/31/2019
- [v0.14.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.14.0.md) released May/22/2019
- [v0.13.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.3.md) released Apr/04/2019
- [v0.13.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.2.md) released Mar/15/2019
- [v0.13.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.1.md) released Feb/9/2019
- [v0.13.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.13.0.md) released Jan/14/2019
- [v0.12.3.4](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.4.md) released Dec/14/2018
- [v0.12.3.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.3.md) released Sep/19/2018
- [v0.12.3.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.2.md) released Jul/09/2018
- [v0.12.3.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.3.1.md) released Jul/03/2018
- [v0.12.2.3](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.3.md) released Jan/12/2018
- [v0.12.2.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.2.md) released Dec/17/2017
- [v0.12.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.2.md) released Nov/08/2017
- [v0.12.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.1.md) released Feb/06/2017
- [v0.12.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.12.0.md) released Aug/15/2015
- [v0.11.2](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.2.md) released Mar/04/2015
- [v0.11.1](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.1.md) released Feb/10/2015
- [v0.11.0](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.11.0.md) released Jan/15/2015
- [v0.10.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.10.0.md) released Sep/25/2014
- [v0.9.x](https://github.com/dashpay/dash/blob/master/doc/release-notes/dash/release-notes-0.9.0.md) released Mar/13/2014

View File

@ -31,6 +31,7 @@ static void SetupWalletToolArgs(ArgsManager& argsman)
// Hidden
argsman.AddArg("salvage", "Attempt to recover private keys from a corrupt wallet", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
argsman.AddArg("wipetxes", "Wipe all transactions from a wallet", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
}
static bool WalletAppInit(int argc, char* argv[])

View File

@ -162,7 +162,7 @@ public:
consensus.DIP0003EnforcementHash = uint256S("000000000000002d1734087b4c5afc3133e4e1c3e1a89218f62bcd9bb3d17f81");
consensus.DIP0008Height = 1088640; // 00000000000000112e41e4b3afda8b233b8cc07c532d2eac5de097b68358c43e
consensus.BRRHeight = 1374912; // 000000000000000c5a124f3eccfbe6e17876dca79cec9e63dfa70d269113c926
consensus.MinBIP9WarningHeight = 1090656; // dip8 activation height + miner confirmation window
consensus.MinBIP9WarningHeight = 1899072 + 2016; // V19 activation height + miner confirmation window
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
consensus.nPowTargetSpacing = 2.5 * 60; // Dash: 2.5 minutes
@ -402,7 +402,7 @@ public:
consensus.DIP0003EnforcementHash = uint256S("00000055ebc0e974ba3a3fb785c5ad4365a39637d4df168169ee80d313612f8f");
consensus.DIP0008Height = 78800; // 000000000e9329d964d80e7dab2e704b43b6bd2b91fea1e9315d38932e55fb55
consensus.BRRHeight = 387500; // 0000001537dbfd09dea69f61c1f8b2afa27c8dc91c934e144797761c9f10367b
consensus.MinBIP9WarningHeight = 80816; // dip8 activation height + miner confirmation window
consensus.MinBIP9WarningHeight = 850100 + 2016; // v19 activation height + miner confirmation window
consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
consensus.nPowTargetSpacing = 2.5 * 60; // Dash: 2.5 minutes
@ -616,7 +616,7 @@ public:
consensus.DIP0003EnforcementHash = uint256();
consensus.DIP0008Height = 2; // DIP0008 activated immediately on devnet
consensus.BRRHeight = 300;
consensus.MinBIP9WarningHeight = 2018; // dip8 activation height + miner confirmation window
consensus.MinBIP9WarningHeight = 300 + 2016; // v19 activation height + miner confirmation window
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1
consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day
consensus.nPowTargetSpacing = 2.5 * 60; // Dash: 2.5 minutes

View File

@ -35,14 +35,8 @@ std::unique_ptr<CCoinJoinClientQueueManager> coinJoinClientQueueManager;
void CCoinJoinClientQueueManager::ProcessMessage(const CNode& peer, std::string_view msg_type, CDataStream& vRecv)
{
if (fMasternodeMode) return;
if (!CCoinJoinClientOptions::IsEnabled()) return;
if (!m_mn_sync->IsBlockchainSynced()) return;
if (!CheckDiskSpace(GetDataDir())) {
LogPrint(BCLog::COINJOIN, "CCoinJoinClientQueueManager::ProcessMessage -- Not enough disk space, disabling CoinJoin.\n");
return;
}
if (msg_type == NetMsgType::DSQUEUE) {
CCoinJoinClientQueueManager::ProcessDSQueue(peer, vRecv);
}
@ -1806,7 +1800,6 @@ void CCoinJoinClientManager::UpdatedBlockTip(const CBlockIndex* pindex)
void CCoinJoinClientQueueManager::DoMaintenance()
{
if (!CCoinJoinClientOptions::IsEnabled()) return;
if (m_mn_sync == nullptr) return;
if (fMasternodeMode) return; // no client-side mixing on masternodes

View File

@ -15,6 +15,7 @@ blspy.*.so
.mypy_cache/
.pytest_chache/
.eggs/
cmake-build-debug/
js_build
node_modules
@ -67,6 +68,8 @@ yarn-error.log
.vs/
out/
target
Makefile.in
/ar-lib
/mdate-sh

View File

@ -14,6 +14,7 @@ endif()
project(BLS)
set(BUILD_BLS_JS_BINDINGS "1" CACHE STRING "")
set(BUILD_BLS_PYTHON_BINDINGS "1" CACHE STRING "")
set(BUILD_BLS_TESTS "1" CACHE STRING "")
set(BUILD_BLS_BENCHMARKS "1" CACHE STRING "")
@ -110,10 +111,36 @@ set(MI_OVERRIDE "off" CACHE STRING "")
add_subdirectory(depends/relic)
add_subdirectory(depends/mimalloc)
#message(STATUS "Patching Relic to make setjmp.h inclusion conditional")
#
#execute_process(
# COMMAND bash -c "git apply ${CMAKE_SOURCE_DIR}/setjmp_patch.diff"
# WORKING_DIRECTORY ${RELIC_SRC}
#)
add_subdirectory(src)
# Write include paths for rust binding
if(EMSCRIPTEN)
add_subdirectory(js-bindings)
file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/include_paths.txt" "${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}/c++/v1/;")
endif()
file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/include_paths.txt" "${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES};")
if(GMP_INCLUDES)
file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/include_paths.txt" "${GMP_INCLUDES};")
endif()
# Write gmp library path for rust binding
if(GMP_LIBRARIES)
file(APPEND "${CMAKE_CURRENT_LIST_DIR}/build/gmp_libraries.txt" "${GMP_LIBRARIES}")
endif()
if(EMSCRIPTEN)
if(BUILD_BLS_JS_BINDINGS)
add_subdirectory(js-bindings)
endif()
else()
# emscripten can't build python bindings, it produces only javascript
# add_subdirectory(contrib/pybind11)

373
src/dashbls/apple.rust.deps.sh Executable file
View File

@ -0,0 +1,373 @@
#!/bin/sh
set -x
# "x86_64-apple-ios"
# "aarch64-apple-ios"
# "aarch64-apple-ios-sim"
# "x86_64-apple-darwin"
# "aarch64-apple-darwin"
# TODO: it's probably needs to be optimized in order to increase better build velocity
# TODO: so we need to combine multiple targets
TARGET=$1
git submodule update --init
MIN_IOS="13.0"
MIN_WATCHOS="5.0"
MIN_TVOS=$MIN_IOS
MIN_MACOS="10.15"
IPHONEOS=iphoneos
IPHONESIMULATOR=iphonesimulator
WATCHOS=watchos
WATCHSIMULATOR=watchsimulator
TVOS=appletvos
TVSIMULATOR=appletvsimulator
MACOS=macosx
LOGICALCPU_MAX=$(sysctl -n hw.logicalcpu_max)
BUILD=build
version_min_flag() {
PLATFORM=$1
FLAG=""
# shellcheck disable=SC2039
# shellcheck disable=SC2053
if [[ $PLATFORM = $IPHONEOS ]]; then
FLAG="-miphoneos-version-min=${MIN_IOS}"
elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then
FLAG="-mios-simulator-version-min=${MIN_IOS}"
elif [[ $PLATFORM = $WATCHOS ]]; then
FLAG="-mwatchos-version-min=${MIN_WATCHOS}"
elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then
FLAG="-mwatchos-simulator-version-min=${MIN_WATCHOS}"
elif [[ $PLATFORM = $TVOS ]]; then
FLAG="-mtvos-version-min=${MIN_TVOS}"
elif [[ $PLATFORM = $TVSIMULATOR ]]; then
FLAG="-mtvos-simulator-version-min=${MIN_TVOS}"
elif [[ $PLATFORM = $MACOS ]]; then
FLAG="-mmacosx-version-min=${MIN_MACOS}"
fi
echo $FLAG
}
prepare() {
download_gmp() {
GMP_VERSION="6.2.1"
CURRENT_DIR=$(pwd)
echo "$CURRENT_DIR"
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
mkdir -p "contrib"
if [ ! -s "contrib/gmp-${GMP_VERSION}.tar.bz2" ]; then
curl -L -o "contrib/gmp-${GMP_VERSION}.tar.bz2" https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2
fi
rm -rf "contrib/gmp"
# shellcheck disable=SC2039,SC2164
pushd contrib
tar xfj "gmp-${GMP_VERSION}.tar.bz2"
mv gmp-${GMP_VERSION} gmp
rm gmp/compat.c && cp ../../contrib/gmp-patch-6.2.1/compat.c gmp/compat.c
rm gmp/longlong.h && cp ../../contrib/gmp-patch-6.2.1/longlong.h gmp/longlong.h
# shellcheck disable=SC2039,SC2164
popd #contrib
# shellcheck disable=SC2039,SC2164
popd #build
}
download_cmake_toolchain() {
if [ ! -s "${BUILD}/ios.toolchain.cmake" ]; then
SHA256_HASH="d02857ff6bd64f1d7109ca59c3e4f3b2f89d0663c412146e6977c679801b3243"
curl -o "${BUILD}/ios.toolchain.cmake" https://raw.githubusercontent.com/leetal/ios-cmake/c55677a4445b138c9ef2650d3c21f22cc78c2357/ios.toolchain.cmake
DOWNLOADED_HASH=$(shasum -a 256 ${BUILD}/ios.toolchain.cmake | cut -f 1 -d " ")
if [ $SHA256_HASH != "$DOWNLOADED_HASH" ]; then
echo "Error: sha256 checksum of ios.toolchain.cmake mismatch" >&2
exit 1
fi
fi
}
download_relic() {
CURRENT_DIR=$(pwd)
echo "$CURRENT_DIR"
mkdir -p "${CURRENT_DIR}/${BUILD}/contrib"
if [ ! -s "${CURRENT_DIR}/${BUILD}/contrib/relic" ]; then
# shellcheck disable=SC2039,SC2164
pushd "${CURRENT_DIR}/${BUILD}/contrib"
git clone --depth 1 --branch "feat/ios-support" https://github.com/pankcuf/relic
# shellcheck disable=SC2039,SC2164
pushd relic
git fetch --depth 1 origin 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae
git checkout 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae
# shellcheck disable=SC2039,SC2164
popd #relic
# shellcheck disable=SC2039,SC2164
popd #contrib
fi
}
rm -rf ${BUILD}
mkdir -p ${BUILD}
download_relic
download_gmp
download_cmake_toolchain
}
build_gmp_arch() {
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
# why this works with this host only?
HOST=arm-apple-darwin
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
PLATFORM_PATH=$(xcrun --sdk "$PLATFORM" --show-sdk-platform-path)
CLANG=$(xcrun --sdk "$PLATFORM" --find clang)
DEVELOPER=$(xcode-select --print-path)
CURRENT_DIR=$(pwd)
export PATH="${PLATFORM_PATH}/Developer/usr/bin:${DEVELOPER}/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin"
mkdir gmplib-"${PLATFORM}"-"${ARCH}"
CFLAGS="-Wno-unused-value -fembed-bitcode -arch ${ARCH} --sysroot=${SDK} $(version_min_flag "$PLATFORM")"
CONFIGURESCRIPT="gmp_configure_script.sh"
# shellcheck disable=SC2039,SC2164
pushd contrib
# shellcheck disable=SC2039,SC2164
pushd gmp
make clean || true
make distclean || true
echo "HOST: $HOST"
echo "PREFIX: ${CURRENT_DIR}/gmplib-${PFX}"
cat >"$CONFIGURESCRIPT" << EOF
#!/bin/sh
./configure \
CC="$CLANG" CFLAGS="$CFLAGS" CPPFLAGS="$CFLAGS" LDFLAGS="$CFLAGS" \
--host=${HOST} --prefix="${CURRENT_DIR}/gmplib-${PFX}" \
--disable-shared --enable-static --disable-assembly -v
EOF
chmod a+x "$CONFIGURESCRIPT"
sh "$CONFIGURESCRIPT"
rm "$CONFIGURESCRIPT"
# shellcheck disable=SC2039
mkdir -p "${CURRENT_DIR}/log"
# shellcheck disable=SC2039
make -j "$LOGICALCPU_MAX" &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-build.log
# shellcheck disable=SC2039
make install &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-install.log
# shellcheck disable=SC2039,SC2164
popd # gmp
# shellcheck disable=SC2039,SC2164
popd # contrib
# shellcheck disable=SC2039,SC2164
popd # build
}
build_relic_arch() {
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
BUILDDIR=relic-"${PFX}"
TOOLCHAIN=$(pwd)/ios.toolchain.cmake
GMP_PFX=$(pwd)/gmplib-${PFX}
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
pushd "$BUILDDIR"
unset CC
# shellcheck disable=SC2155
export CC=$(xcrun --sdk "${PLATFORM}" --find clang)
WSIZE=0
IOS_PLATFORM=""
OPTIMIZATIONFLAGS=""
DEPLOYMENT_TARGET=""
# shellcheck disable=SC2039
# shellcheck disable=SC2053
if [[ $PLATFORM = $IPHONEOS ]]; then
if [[ $ARCH = "arm64" ]] || [[ $ARCH = "arm64e" ]]; then
IOS_PLATFORM=OS64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
else
IOS_PLATFORM=OS
WSIZE=32
fi
elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then
if [[ $ARCH = "x86_64" ]]; then
IOS_PLATFORM=SIMULATOR64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $ARCH = "arm64" ]]; then
IOS_PLATFORM=SIMULATORARM64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
else
IOS_PLATFORM=SIMULATOR
WSIZE=32
fi
elif [[ $PLATFORM = $WATCHOS ]]; then
IOS_PLATFORM=WATCHOS
DEPLOYMENT_TARGET=$MIN_WATCHOS
WSIZE=32
elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then
IOS_PLATFORM=SIMULATOR_WATCHOS
DEPLOYMENT_TARGET=$MIN_WATCHOS
WSIZE=32
elif [[ $PLATFORM = $TVOS ]]; then
IOS_PLATFORM=TVOS
DEPLOYMENT_TARGET=$MIN_TVOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $PLATFORM = $TVSIMULATOR ]]; then
IOS_PLATFORM=SIMULATOR_TVOS
#TODO
if [[ $ARCH = "arm64" ]]
then
IOS_PLATFORM=OS64
fi
DEPLOYMENT_TARGET=$MIN_TVOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $PLATFORM = $MACOS ]]; then
WSIZE=64
IOS_PLATFORM=MAC
if [[ $ARCH = "arm64" ]]
then
IOS_PLATFORM=MAC_ARM64
fi
DEPLOYMENT_TARGET=$MIN_MACOS
OPTIMIZATIONFLAGS=-fomit-frame-pointer
fi
COMPILER_ARGS="$(version_min_flag "$PLATFORM") -Wno-unused-functions"
EXTRA_ARGS="-DOPSYS=NONE -DPLATFORM=$IOS_PLATFORM -DDEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN"
# shellcheck disable=SC2039
if [[ $ARCH = "i386" ]]; then
EXTRA_ARGS+=" -DARCH=X86"
elif [[ $ARCH = "x86_64" ]]; then
EXTRA_ARGS+=" -DARCH=X64"
else
EXTRA_ARGS+=" -DARCH=ARM"
if [[ $ARCH = "armv7s" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=armv7s"
elif [[ $ARCH = "armv7k" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=armv7k"
elif [[ $ARCH = "arm64_32" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=arm64_32"
fi
fi
CURRENT_DIR=$(pwd)
cmake -DCMAKE_PREFIX_PATH:PATH="${GMP_PFX}" -DTESTS=0 -DBENCH=0 -DBUILD_BLS_JS_BINDINGS=0 -DBUILD_BLS_PYTHON_BINDINGS=0 \
-DBUILD_BLS_BENCHMARKS=0 -DBUILD_BLS_TESTS=0 -DCHECK=off -DARITH=gmp -DTIMER=HPROC -DFP_PRIME=381 -DMULTI=PTHREAD \
-DFP_QNRES=on -DFP_METHD="INTEG;INTEG;INTEG;MONTY;EXGCD;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \
-DCOMP_FLAGS="-pipe -std=c99 -O3 -funroll-loops $OPTIMIZATIONFLAGS -isysroot $SDK -arch $ARCH -fembed-bitcode ${COMPILER_ARGS}" \
-DWSIZE=$WSIZE -DVERBS=off -DSHLIB=off -DALLOC="AUTO" -DEP_PLAIN=off -DEP_SUPER=off -DPP_EXT="LAZYR" \
-DWITH="DV;BN;MD;FP;EP;FPX;EPX;PP;PC;CP" -DBN_METHD="COMBA;COMBA;MONTY;SLIDE;STEIN;BASIC" ${EXTRA_ARGS} ../../
make -j "$LOGICALCPU_MAX"
# shellcheck disable=SC2039,SC2164
popd # "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
popd # contrib/relic
}
build_bls_arch() {
# shellcheck disable=SC2039
BLS_FILES=( "bls" "chaincode" "elements" "extendedprivatekey" "extendedpublickey" "legacy" "privatekey" "schemes" "threshold" )
# shellcheck disable=SC2039
ALL_BLS_OBJ_FILES=$(printf "%s.o " "${BLS_FILES[@]}")
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
BUILDDIR=${BUILD}/bls-"${PFX}"
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
pushd "$BUILDDIR"
EXTRA_ARGS="$(version_min_flag "$PLATFORM")"
CURRENT_DIR=$(pwd)
# shellcheck disable=SC2039
for F in "${BLS_FILES[@]}"
do
clang -I"../contrib/relic/include" \
-I"../../depends/relic/include" \
-I"../../include/dashbls" \
-I"../relic-${PFX}/_deps/relic-build/include" \
-I"../../src/" \
-I"../gmplib-${PFX}/include" \
-x c++ -std=c++14 -stdlib=libc++ -fembed-bitcode -arch "${ARCH}" -isysroot "${SDK}" "${EXTRA_ARGS}" \
-c "../../src/${F}.cpp" -o "${F}.o"
done
# shellcheck disable=SC2086
xcrun -sdk "$PLATFORM" ar -cvq libbls.a $ALL_BLS_OBJ_FILES
# shellcheck disable=SC2039,SC2164
popd # "$BUILDDIR"
}
build_all_arch() {
PLATFORM=$1
ARCH=$2
build_gmp_arch "$PLATFORM" "$ARCH"
build_relic_arch "$PLATFORM" "$ARCH"
build_bls_arch "$PLATFORM" "$ARCH"
}
build_target() {
BUILD_IN=$1
echo "Build target: $BUILD_IN"
ARCH=""
PLATFORM=""
# shellcheck disable=SC2039
if [[ $BUILD_IN = "x86_64-apple-ios" ]]; then
ARCH=x86_64
PLATFORM=$IPHONESIMULATOR
elif [[ $BUILD_IN = "aarch64-apple-ios" ]]; then
ARCH=arm64
PLATFORM=$IPHONEOS
elif [[ $BUILD_IN = "aarch64-apple-ios-sim" ]]; then
ARCH=arm64
PLATFORM=$IPHONESIMULATOR
elif [[ $BUILD_IN = "x86_64-apple-darwin" ]]; then
ARCH=x86_64
PLATFORM=$MACOS
elif [[ $BUILD_IN = "aarch64-apple-darwin" ]]; then
ARCH=arm64
PLATFORM=$MACOS
fi
build_all_arch "$PLATFORM" "$ARCH"
PFX="${PLATFORM}"-"${ARCH}"
rm -rf "build/artefacts/${BUILD_IN}"
mkdir -p "build/artefacts/${BUILD_IN}"
cp "build/gmplib-${PFX}/lib/libgmp.a" "build/artefacts/${BUILD_IN}"
cp "build/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" "build/artefacts/${BUILD_IN}"
cp "build/relic-${PFX}/_deps/sodium-build/libsodium.a" "build/artefacts/${BUILD_IN}"
cp "build/bls-${PFX}/libbls.a" "build/artefacts/${BUILD_IN}"
# cp -rf build/bls-"${PFX}"/*.o build/artefacts/"${BUILD_IN}"/include
# cp -rf src/*.hpp build/artefacts/"${BUILD_IN}"/include
# cp -rf build/gmplib-"${PFX}"/include/gmp.h build/artefacts/"${BUILD_IN}"/include
# cp -rf build/relic-"${PFX}"/_deps/relic-build/include/*.h build/artefacts/"${BUILD_IN}"/include
}
prepare
build_target "$TARGET"

458
src/dashbls/apple.rust.sh Executable file
View File

@ -0,0 +1,458 @@
#!/bin/sh
set -x
git submodule update --init
MIN_IOS="13.0"
MIN_WATCHOS="5.0"
MIN_TVOS=$MIN_IOS
MIN_MACOS="10.15"
IPHONEOS=iphoneos
IPHONESIMULATOR=iphonesimulator
WATCHOS=watchos
WATCHSIMULATOR=watchsimulator
TVOS=appletvos
TVSIMULATOR=appletvsimulator
MACOS=macosx
LOGICALCPU_MAX=$(sysctl -n hw.logicalcpu_max)
BUILD=build
version_min_flag() {
PLATFORM=$1
FLAG=""
# shellcheck disable=SC2039
# shellcheck disable=SC2053
if [[ $PLATFORM = $IPHONEOS ]]; then
FLAG="-miphoneos-version-min=${MIN_IOS}"
elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then
FLAG="-mios-simulator-version-min=${MIN_IOS}"
elif [[ $PLATFORM = $WATCHOS ]]; then
FLAG="-mwatchos-version-min=${MIN_WATCHOS}"
elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then
FLAG="-mwatchos-simulator-version-min=${MIN_WATCHOS}"
elif [[ $PLATFORM = $TVOS ]]; then
FLAG="-mtvos-version-min=${MIN_TVOS}"
elif [[ $PLATFORM = $TVSIMULATOR ]]; then
FLAG="-mtvos-simulator-version-min=${MIN_TVOS}"
elif [[ $PLATFORM = $MACOS ]]; then
FLAG="-mmacosx-version-min=${MIN_MACOS}"
fi
echo $FLAG
}
prepare() {
download_gmp() {
GMP_VERSION="6.2.1"
CURRENT_DIR=$(pwd)
echo "$CURRENT_DIR"
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
mkdir -p "contrib"
if [ ! -s "contrib/gmp-${GMP_VERSION}.tar.bz2" ]; then
curl -L -o "contrib/gmp-${GMP_VERSION}.tar.bz2" https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2
fi
rm -rf "contrib/gmp"
# shellcheck disable=SC2039,SC2164
pushd contrib
tar xfj "gmp-${GMP_VERSION}.tar.bz2"
mv gmp-${GMP_VERSION} gmp
rm gmp/compat.c && cp ../../contrib/gmp-patch-6.2.1/compat.c gmp/compat.c
rm gmp/longlong.h && cp ../../contrib/gmp-patch-6.2.1/longlong.h gmp/longlong.h
# shellcheck disable=SC2039,SC2164
popd #contrib
# shellcheck disable=SC2039,SC2164
popd #build
}
download_cmake_toolchain() {
if [ ! -s "${BUILD}/ios.toolchain.cmake" ]; then
SHA256_HASH="d02857ff6bd64f1d7109ca59c3e4f3b2f89d0663c412146e6977c679801b3243"
curl -o "${BUILD}/ios.toolchain.cmake" https://raw.githubusercontent.com/leetal/ios-cmake/c55677a4445b138c9ef2650d3c21f22cc78c2357/ios.toolchain.cmake
DOWNLOADED_HASH=$(shasum -a 256 ${BUILD}/ios.toolchain.cmake | cut -f 1 -d " ")
if [ $SHA256_HASH != "$DOWNLOADED_HASH" ]; then
echo "Error: sha256 checksum of ios.toolchain.cmake mismatch" >&2
exit 1
fi
fi
}
download_relic() {
CURRENT_DIR=$(pwd)
echo "$CURRENT_DIR"
mkdir -p "${CURRENT_DIR}/${BUILD}/contrib"
if [ ! -s "${CURRENT_DIR}/${BUILD}/contrib/relic" ]; then
# shellcheck disable=SC2039,SC2164
pushd "${CURRENT_DIR}/${BUILD}/contrib"
git clone --depth 1 --branch "feat/ios-support" https://github.com/pankcuf/relic
# shellcheck disable=SC2039,SC2164
pushd relic
git fetch --depth 1 origin 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae
git checkout 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae
# shellcheck disable=SC2039,SC2164
popd #relic
# shellcheck disable=SC2039,SC2164
popd #contrib
fi
}
rm -rf ${BUILD}
mkdir -p ${BUILD}
download_relic
download_gmp
download_cmake_toolchain
mkdir -p ${BUILD}/artefacts/include
}
build_gmp_arch() {
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
# why this works with this host only?
HOST=arm-apple-darwin
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
PLATFORM_PATH=$(xcrun --sdk "$PLATFORM" --show-sdk-platform-path)
CLANG=$(xcrun --sdk "$PLATFORM" --find clang)
DEVELOPER=$(xcode-select --print-path)
CURRENT_DIR=$(pwd)
export PATH="${PLATFORM_PATH}/Developer/usr/bin:${DEVELOPER}/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin"
mkdir gmplib-"${PLATFORM}"-"${ARCH}"
CFLAGS="-Wno-unused-value -fembed-bitcode -arch ${ARCH} --sysroot=${SDK} $(version_min_flag "$PLATFORM")"
CONFIGURESCRIPT="gmp_configure_script.sh"
# shellcheck disable=SC2039,SC2164
pushd contrib
# shellcheck disable=SC2039,SC2164
pushd gmp
make clean || true
make distclean || true
echo "HOST: $HOST"
echo "PREFIX: ${CURRENT_DIR}/gmplib-${PFX}"
cat >"$CONFIGURESCRIPT" << EOF
#!/bin/sh
./configure \
CC="$CLANG" CFLAGS="$CFLAGS" CPPFLAGS="$CFLAGS" LDFLAGS="$CFLAGS" \
--host=${HOST} --prefix="${CURRENT_DIR}/gmplib-${PFX}" \
--disable-shared --enable-static --disable-assembly -v
EOF
chmod a+x "$CONFIGURESCRIPT"
sh "$CONFIGURESCRIPT"
rm "$CONFIGURESCRIPT"
# shellcheck disable=SC2039
mkdir -p "${CURRENT_DIR}/log"
# shellcheck disable=SC2039
make -j "$LOGICALCPU_MAX" &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-build.log
# shellcheck disable=SC2039
make install &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-install.log
# shellcheck disable=SC2039,SC2164
popd # gmp
# shellcheck disable=SC2039,SC2164
popd # contrib
# shellcheck disable=SC2039,SC2164
popd # build
}
build_relic_arch() {
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
BUILDDIR=relic-"${PFX}"
TOOLCHAIN=$(pwd)/ios.toolchain.cmake
GMP_PFX=$(pwd)/gmplib-${PFX}
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
pushd "$BUILDDIR"
unset CC
# shellcheck disable=SC2155
export CC=$(xcrun --sdk "${PLATFORM}" --find clang)
WSIZE=0
IOS_PLATFORM=""
OPTIMIZATIONFLAGS=""
DEPLOYMENT_TARGET=""
# shellcheck disable=SC2039
# shellcheck disable=SC2053
if [[ $PLATFORM = $IPHONEOS ]]; then
if [[ $ARCH = "arm64" ]] || [[ $ARCH = "arm64e" ]]; then
IOS_PLATFORM=OS64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
else
IOS_PLATFORM=OS
WSIZE=32
fi
elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then
if [[ $ARCH = "x86_64" ]]; then
IOS_PLATFORM=SIMULATOR64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $ARCH = "arm64" ]]; then
IOS_PLATFORM=SIMULATORARM64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
else
IOS_PLATFORM=SIMULATOR
WSIZE=32
fi
elif [[ $PLATFORM = $WATCHOS ]]; then
IOS_PLATFORM=WATCHOS
DEPLOYMENT_TARGET=$MIN_WATCHOS
WSIZE=32
elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then
IOS_PLATFORM=SIMULATOR_WATCHOS
DEPLOYMENT_TARGET=$MIN_WATCHOS
WSIZE=32
elif [[ $PLATFORM = $TVOS ]]; then
IOS_PLATFORM=TVOS
DEPLOYMENT_TARGET=$MIN_TVOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $PLATFORM = $TVSIMULATOR ]]; then
IOS_PLATFORM=SIMULATOR_TVOS
#TODO
if [[ $ARCH = "arm64" ]]
then
IOS_PLATFORM=OS64
fi
DEPLOYMENT_TARGET=$MIN_TVOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $PLATFORM = $MACOS ]]; then
WSIZE=64
IOS_PLATFORM=MAC
if [[ $ARCH = "arm64" ]]
then
IOS_PLATFORM=MAC_ARM64
fi
DEPLOYMENT_TARGET=$MIN_MACOS
OPTIMIZATIONFLAGS=-fomit-frame-pointer
fi
COMPILER_ARGS="$(version_min_flag "$PLATFORM") -Wno-unused-functions"
EXTRA_ARGS="-DOPSYS=NONE -DPLATFORM=$IOS_PLATFORM -DDEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN"
# shellcheck disable=SC2039
if [[ $ARCH = "i386" ]]; then
EXTRA_ARGS+=" -DARCH=X86"
elif [[ $ARCH = "x86_64" ]]; then
EXTRA_ARGS+=" -DARCH=X64"
else
EXTRA_ARGS+=" -DARCH=ARM"
if [[ $ARCH = "armv7s" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=armv7s"
elif [[ $ARCH = "armv7k" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=armv7k"
elif [[ $ARCH = "arm64_32" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=arm64_32"
fi
fi
CURRENT_DIR=$(pwd)
cmake -DCMAKE_PREFIX_PATH:PATH="${GMP_PFX}" -DTESTS=0 -DBENCH=0 -DBUILD_BLS_JS_BINDINGS=0 -DBUILD_BLS_PYTHON_BINDINGS=0 \
-DBUILD_BLS_BENCHMARKS=0 -DBUILD_BLS_TESTS=0 -DCHECK=off -DARITH=gmp -DTIMER=HPROC -DFP_PRIME=381 -DMULTI=PTHREAD \
-DFP_QNRES=on -DFP_METHD="INTEG;INTEG;INTEG;MONTY;EXGCD;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \
-DCOMP_FLAGS="-pipe -std=c99 -O3 -funroll-loops $OPTIMIZATIONFLAGS -isysroot $SDK -arch $ARCH -fembed-bitcode ${COMPILER_ARGS}" \
-DWSIZE=$WSIZE -DVERBS=off -DSHLIB=off -DALLOC="AUTO" -DEP_PLAIN=off -DEP_SUPER=off -DPP_EXT="LAZYR" \
-DWITH="DV;BN;MD;FP;EP;FPX;EPX;PP;PC;CP" -DBN_METHD="COMBA;COMBA;MONTY;SLIDE;STEIN;BASIC" ${EXTRA_ARGS} ../../
make -j "$LOGICALCPU_MAX"
# shellcheck disable=SC2039,SC2164
popd # "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
popd # contrib/relic
}
build_bls_arch() {
# shellcheck disable=SC2039
BLS_FILES=( "bls" "chaincode" "elements" "extendedprivatekey" "extendedpublickey" "legacy" "privatekey" "schemes" "threshold" )
# shellcheck disable=SC2039
ALL_BLS_OBJ_FILES=$(printf "%s.o " "${BLS_FILES[@]}")
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
BUILDDIR=${BUILD}/bls-"${PFX}"
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
pushd "$BUILDDIR"
EXTRA_ARGS="$(version_min_flag "$PLATFORM")"
CURRENT_DIR=$(pwd)
# shellcheck disable=SC2039
for F in "${BLS_FILES[@]}"
do
clang -I"../contrib/relic/include" \
-I"../relic-${PFX}/_deps/relic-build/include" \
-I"../../src/" \
-I"../gmplib-${PFX}/include" \
-x c++ -std=c++14 -stdlib=libc++ -fembed-bitcode -arch "${ARCH}" -isysroot "${SDK}" "${EXTRA_ARGS}" \
-c "../../src/${F}.cpp" -o "${F}.o"
done
# shellcheck disable=SC2086
xcrun -sdk "$PLATFORM" ar -cvq libbls.a $ALL_BLS_OBJ_FILES
# shellcheck disable=SC2039,SC2164
popd # "$BUILDDIR"
}
build_all_arch() {
PLATFORM=$1
ARCH=$2
build_gmp_arch "$PLATFORM" "$ARCH"
build_relic_arch "$PLATFORM" "$ARCH"
build_bls_arch "$PLATFORM" "$ARCH"
}
build_all() {
BUILD_IN=$1
TARGET_DIR=build/artefacts
# shellcheck disable=SC2039
IFS='|' read -ra BUILD_PAIRS <<< "$BUILD_IN"
# shellcheck disable=SC2039
for BUILD_PAIR in "${BUILD_PAIRS[@]}"
do
# shellcheck disable=SC2039
IFS=';' read -ra PARSED_PAIR <<< "$BUILD_PAIR"
# shellcheck disable=SC2039
PLATFORM=${PARSED_PAIR[0]}
# shellcheck disable=SC2039
ARCH=${PARSED_PAIR[1]}
GMP_LIPOARGS=""
RELIC_LIPOARGS=""
BLS_LIPOARGS=""
# shellcheck disable=SC2039
local NEED_LIPO=0
# shellcheck disable=SC2039
IFS='+' read -ra ARCHS <<< "$ARCH"
# shellcheck disable=SC2039
for i in "${!ARCHS[@]}"
do
# shellcheck disable=SC2039
local SINGLEARCH=${ARCHS[i]}
# build for every platform+arch
build_all_arch "$PLATFORM" "$SINGLEARCH"
PFX="${PLATFORM}"-"${SINGLEARCH}"
ARCH_TARGET_DIR=${TARGET_DIR}/${PFX}
rm -rf "${ARCH_TARGET_DIR}"
mkdir -p "${ARCH_TARGET_DIR}"
#mv "${BUILD}/gmplib-${PFX}/lib/libgmp.a" "${ARCH_TARGET_DIR}/libgmp.a"
#mv "${BUILD}/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" "${ARCH_TARGET_DIR}/librelic.a"
#mv "${BUILD}/bls-${PFX}/libbls.a" "${ARCH_TARGET_DIR}/libbls.a"
libtool -static -o "${ARCH_TARGET_DIR}/libbls.a" \
"${BUILD}/gmplib-${PFX}/lib/libgmp.a" \
"${BUILD}/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" \
"${BUILD}/bls-${PFX}/libbls.a"
# shellcheck disable=SC2039
GMP_LIPOARGS+="${ARCH_TARGET_DIR}/libgmp.a "
# shellcheck disable=SC2039
RELIC_LIPOARGS+="${ARCH_TARGET_DIR}/librelic.a "
# shellcheck disable=SC2039
BLS_LIPOARGS+="${ARCH_TARGET_DIR}/libbls.a "
NEED_LIPO=i
done
# Do lipo if we need https://developer.apple.com/forums/thread/666335?answerId=645963022#645963022
# if [[ $NEED_LIPO -gt 0 ]]
# then
# FAT_TARGET_DIR=${TARGET_DIR}/${PLATFORM}-fat
# rm -rf "${FAT_TARGET_DIR}"
# mkdir -p "${FAT_TARGET_DIR}"
# # shellcheck disable=SC2086
# xcrun lipo $GMP_LIPOARGS -create -output "${FAT_TARGET_DIR}/libgmp.a"
# # shellcheck disable=SC2086
# xcrun lipo $RELIC_LIPOARGS -create -output "${FAT_TARGET_DIR}/librelic.a"
# # shellcheck disable=SC2086
# xcrun lipo $BLS_LIPOARGS -create -output "${FAT_TARGET_DIR}/libbls.a"
# libtool -static -o "${FAT_TARGET_DIR}/libbls_combined.a" "${FAT_TARGET_DIR}/libgmp.a" "${FAT_TARGET_DIR}/librelic.a" "${FAT_TARGET_DIR}/libbls.a"
# rm "${FAT_TARGET_DIR}/libgmp.a"
# rm "${FAT_TARGET_DIR}/librelic.a"
# rm "${FAT_TARGET_DIR}/libbls.a"
# mv "${FAT_TARGET_DIR}/libbls_combined.a" "${FAT_TARGET_DIR}/libbls.a"
# # clean up
# # shellcheck disable=SC2039
# for i in "${!ARCHS[@]}"
# do
# local SINGLEARCH=${ARCHS[i]}
# rm -rf "${TARGET_DIR}-${SINGLEARCH}"
# done
# fi
done
}
#make_relic_headers_universal() {
# RELIC_TARGET_DIR=relic-iphoneos-arm64
# perl -p -e 's/#define WSIZE.*/#ifdef __LP64__\n#define WSIZE 64\n#else\n#define WSIZE 32\n#endif/' \
# "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" \
# > "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new"
#
# rm "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h"
# mv "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new" "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h"
#}
#copy_headers() {
# mkdir build/artefacts/include
# # Copy all headers we will need
# cp -rf src/*.hpp build/artefacts/include
# cp -rf build/gmp/include/gmp.h build/artefacts/include
# cp -rf build/contrib/relic/include/*.h build/artefacts/include
# cp -rf build/contrib/relic/include/low/*.h build/artefacts/include
# cp -rf build/contrib/relic/relic-iphoneos-arm64/include/*.h build/artefacts/include
# rm -rf build/artefacts/include/test-utils.hpp
#}
#function make_fat_binary()
#{
# pushd artefacts
#
# XCFRAMEWORK_ARGS=""
#
# for dir in */; do
# if [ -d "$dir" ]; then
# if [[ "$dir" != "include/" ]]; then
# libtool -static -o "${dir}libbls_combined.a" "${dir}libgmp.a" "${dir}librelic.a" "${dir}libbls.a"
#
# XCFRAMEWORK_ARGS+="-library ${dir}libbls_combined.a -headers include "
# fi
# fi
# done
#
# #xcodebuild -create-xcframework $XCFRAMEWORK_ARGS -output "libbls.xcframework"
#}
prepare
build_all "${MACOS};x86_64+arm64"
build_all "${IPHONEOS};arm64|${IPHONESIMULATOR};arm64+x86_64"
#make_relic_headers_universal
#copy_headers
#make_fat_binary

404
src/dashbls/apple.rust.single.sh Executable file
View File

@ -0,0 +1,404 @@
#!/bin/sh
set -x
# "x86_64-apple-ios"
# "x86_64-apple-ios-sim"
# "aarch64-apple-ios"
# "aarch64-apple-ios-sim"
# "x86_64-apple-darwin"
# "aarch64-apple-darwin"
# TODO: it's probably needs to be optimized in order to increase better build velocity
# TODO: so we need to combine multiple targets
TARGET=$1
git submodule update --init
MIN_IOS="13.0"
MIN_WATCHOS="5.0"
MIN_TVOS=$MIN_IOS
MIN_MACOS="10.15"
IPHONEOS=iphoneos
IPHONESIMULATOR=iphonesimulator
WATCHOS=watchos
WATCHSIMULATOR=watchsimulator
TVOS=appletvos
TVSIMULATOR=appletvsimulator
MACOS=macosx
LOGICALCPU_MAX=$(sysctl -n hw.logicalcpu_max)
BUILD=build
version_min_flag() {
PLATFORM=$1
FLAG=""
# shellcheck disable=SC2039
# shellcheck disable=SC2053
if [[ $PLATFORM = $IPHONEOS ]]; then
FLAG="-miphoneos-version-min=${MIN_IOS}"
elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then
FLAG="-mios-simulator-version-min=${MIN_IOS}"
elif [[ $PLATFORM = $WATCHOS ]]; then
FLAG="-mwatchos-version-min=${MIN_WATCHOS}"
elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then
FLAG="-mwatchos-simulator-version-min=${MIN_WATCHOS}"
elif [[ $PLATFORM = $TVOS ]]; then
FLAG="-mtvos-version-min=${MIN_TVOS}"
elif [[ $PLATFORM = $TVSIMULATOR ]]; then
FLAG="-mtvos-simulator-version-min=${MIN_TVOS}"
elif [[ $PLATFORM = $MACOS ]]; then
FLAG="-mmacosx-version-min=${MIN_MACOS}"
fi
echo $FLAG
}
prepare() {
download_gmp() {
GMP_VERSION="6.2.1"
CURRENT_DIR=$(pwd)
echo "$CURRENT_DIR"
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
mkdir -p "contrib"
if [ ! -s "contrib/gmp-${GMP_VERSION}.tar.bz2" ]; then
curl -L -o "contrib/gmp-${GMP_VERSION}.tar.bz2" https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2
fi
rm -rf "contrib/gmp"
# shellcheck disable=SC2039,SC2164
pushd contrib
tar xfj "gmp-${GMP_VERSION}.tar.bz2"
mv gmp-${GMP_VERSION} gmp
rm gmp/compat.c && cp ../../contrib/gmp-patch-6.2.1/compat.c gmp/compat.c
rm gmp/longlong.h && cp ../../contrib/gmp-patch-6.2.1/longlong.h gmp/longlong.h
# shellcheck disable=SC2039,SC2164
popd #contrib
# shellcheck disable=SC2039,SC2164
popd #build
}
download_cmake_toolchain() {
if [ ! -s "${BUILD}/ios.toolchain.cmake" ]; then
SHA256_HASH="d02857ff6bd64f1d7109ca59c3e4f3b2f89d0663c412146e6977c679801b3243"
curl -o "${BUILD}/ios.toolchain.cmake" https://raw.githubusercontent.com/leetal/ios-cmake/c55677a4445b138c9ef2650d3c21f22cc78c2357/ios.toolchain.cmake
DOWNLOADED_HASH=$(shasum -a 256 ${BUILD}/ios.toolchain.cmake | cut -f 1 -d " ")
if [ $SHA256_HASH != "$DOWNLOADED_HASH" ]; then
echo "Error: sha256 checksum of ios.toolchain.cmake mismatch" >&2
exit 1
fi
fi
}
download_relic() {
CURRENT_DIR=$(pwd)
echo "$CURRENT_DIR"
mkdir -p "${CURRENT_DIR}/${BUILD}/contrib"
if [ ! -s "${CURRENT_DIR}/${BUILD}/contrib/relic" ]; then
# shellcheck disable=SC2039,SC2164
pushd "${CURRENT_DIR}/${BUILD}/contrib"
git clone --depth 1 --branch "feat/ios-support" https://github.com/pankcuf/relic
# shellcheck disable=SC2039,SC2164
pushd relic
git fetch --depth 1 origin 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae
git checkout 19fb6d79a77ade4ae8cd70d2b0ef7aab8720d1ae
# shellcheck disable=SC2039,SC2164
popd #relic
# shellcheck disable=SC2039,SC2164
popd #contrib
fi
}
rm -rf ${BUILD}
mkdir -p ${BUILD}
download_relic
download_gmp
download_cmake_toolchain
}
build_gmp_arch() {
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
# why this works with this host only?
HOST=arm-apple-darwin
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
PLATFORM_PATH=$(xcrun --sdk "$PLATFORM" --show-sdk-platform-path)
CLANG=$(xcrun --sdk "$PLATFORM" --find clang)
DEVELOPER=$(xcode-select --print-path)
CURRENT_DIR=$(pwd)
export PATH="${PLATFORM_PATH}/Developer/usr/bin:${DEVELOPER}/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/homebrew/bin"
mkdir gmplib-"${PLATFORM}"-"${ARCH}"
CFLAGS="-Wno-unused-value -fembed-bitcode -arch ${ARCH} --sysroot=${SDK} $(version_min_flag "$PLATFORM")"
CONFIGURESCRIPT="gmp_configure_script.sh"
# shellcheck disable=SC2039,SC2164
pushd contrib
# shellcheck disable=SC2039,SC2164
pushd gmp
make clean || true
make distclean || true
echo "HOST: $HOST"
echo "PREFIX: ${CURRENT_DIR}/gmplib-${PFX}"
cat >"$CONFIGURESCRIPT" << EOF
#!/bin/sh
./configure \
CC="$CLANG" CFLAGS="$CFLAGS" CPPFLAGS="$CFLAGS" LDFLAGS="$CFLAGS" \
--host=${HOST} --prefix="${CURRENT_DIR}/gmplib-${PFX}" \
--disable-shared --enable-static --disable-assembly -v
EOF
chmod a+x "$CONFIGURESCRIPT"
sh "$CONFIGURESCRIPT"
rm "$CONFIGURESCRIPT"
# shellcheck disable=SC2039
mkdir -p "${CURRENT_DIR}/log"
# shellcheck disable=SC2039
make -j "$LOGICALCPU_MAX" &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-build.log
# shellcheck disable=SC2039
make install &> "${CURRENT_DIR}"/log/gmplib-"${PFX}"-install.log
# shellcheck disable=SC2039,SC2164
popd # gmp
# shellcheck disable=SC2039,SC2164
popd # contrib
# shellcheck disable=SC2039,SC2164
popd # build
}
build_relic_arch() {
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
# shellcheck disable=SC2039,SC2164
pushd ${BUILD}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
BUILDDIR=relic-"${PFX}"
TOOLCHAIN=$(pwd)/ios.toolchain.cmake
GMP_PFX=$(pwd)/gmplib-${PFX}
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
pushd "$BUILDDIR"
unset CC
# shellcheck disable=SC2155
export CC=$(xcrun --sdk "${PLATFORM}" --find clang)
WSIZE=0
IOS_PLATFORM=""
OPTIMIZATIONFLAGS=""
DEPLOYMENT_TARGET=""
# shellcheck disable=SC2039
# shellcheck disable=SC2053
if [[ $PLATFORM = $IPHONEOS ]]; then
if [[ $ARCH = "arm64" ]] || [[ $ARCH = "arm64e" ]]; then
IOS_PLATFORM=OS64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
else
IOS_PLATFORM=OS
WSIZE=32
fi
elif [[ $PLATFORM = $IPHONESIMULATOR ]]; then
if [[ $ARCH = "x86_64" ]]; then
IOS_PLATFORM=SIMULATOR64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $ARCH = "arm64" ]]; then
IOS_PLATFORM=SIMULATORARM64
DEPLOYMENT_TARGET=$MIN_IOS
WSIZE=64
else
IOS_PLATFORM=SIMULATOR
WSIZE=32
fi
elif [[ $PLATFORM = $WATCHOS ]]; then
IOS_PLATFORM=WATCHOS
DEPLOYMENT_TARGET=$MIN_WATCHOS
WSIZE=32
elif [[ $PLATFORM = $WATCHSIMULATOR ]]; then
IOS_PLATFORM=SIMULATOR_WATCHOS
DEPLOYMENT_TARGET=$MIN_WATCHOS
WSIZE=32
elif [[ $PLATFORM = $TVOS ]]; then
IOS_PLATFORM=TVOS
DEPLOYMENT_TARGET=$MIN_TVOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $PLATFORM = $TVSIMULATOR ]]; then
IOS_PLATFORM=SIMULATOR_TVOS
#TODO
if [[ $ARCH = "arm64" ]]
then
IOS_PLATFORM=OS64
fi
DEPLOYMENT_TARGET=$MIN_TVOS
WSIZE=64
OPTIMIZATIONFLAGS=-fomit-frame-pointer
elif [[ $PLATFORM = $MACOS ]]; then
WSIZE=64
IOS_PLATFORM=MAC
if [[ $ARCH = "arm64" ]]
then
IOS_PLATFORM=MAC_ARM64
fi
DEPLOYMENT_TARGET=$MIN_MACOS
OPTIMIZATIONFLAGS=-fomit-frame-pointer
fi
COMPILER_ARGS="$(version_min_flag "$PLATFORM") -Wno-unused-functions"
EXTRA_ARGS="-DOPSYS=NONE -DPLATFORM=$IOS_PLATFORM -DDEPLOYMENT_TARGET=$DEPLOYMENT_TARGET -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN"
# shellcheck disable=SC2039
if [[ $ARCH = "i386" ]]; then
EXTRA_ARGS+=" -DARCH=X86"
elif [[ $ARCH = "x86_64" ]]; then
EXTRA_ARGS+=" -DARCH=X64"
else
EXTRA_ARGS+=" -DARCH=ARM"
if [[ $ARCH = "armv7s" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=armv7s"
elif [[ $ARCH = "armv7k" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=armv7k"
elif [[ $ARCH = "arm64_32" ]]; then
EXTRA_ARGS+=" -DIOS_ARCH=arm64_32"
fi
fi
CURRENT_DIR=$(pwd)
cmake -DCMAKE_PREFIX_PATH:PATH="${GMP_PFX}" -DTESTS=0 -DBENCH=0 -DBUILD_BLS_JS_BINDINGS=0 -DBUILD_BLS_PYTHON_BINDINGS=0 \
-DBUILD_BLS_BENCHMARKS=0 -DBUILD_BLS_TESTS=0 -DCHECK=off -DARITH=gmp -DTIMER=HPROC -DFP_PRIME=381 -DMULTI=PTHREAD \
-DFP_QNRES=on -DFP_METHD="INTEG;INTEG;INTEG;MONTY;EXGCD;SLIDE" -DFPX_METHD="INTEG;INTEG;LAZYR" -DPP_METHD="LAZYR;OATEP" \
-DCOMP_FLAGS="-pipe -std=c99 -O3 -funroll-loops $OPTIMIZATIONFLAGS -isysroot $SDK -arch $ARCH -fembed-bitcode ${COMPILER_ARGS}" \
-DWSIZE=$WSIZE -DVERBS=off -DSHLIB=off -DALLOC="AUTO" -DEP_PLAIN=off -DEP_SUPER=off -DPP_EXT="LAZYR" \
-DWITH="DV;BN;MD;FP;EP;FPX;EPX;PP;PC;CP" -DBN_METHD="COMBA;COMBA;MONTY;SLIDE;STEIN;BASIC" ${EXTRA_ARGS} ../../
make -j "$LOGICALCPU_MAX"
# shellcheck disable=SC2039,SC2164
popd # "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
popd # contrib/relic
}
build_bls_arch() {
# shellcheck disable=SC2039
BLS_FILES=( "bls" "chaincode" "elements" "extendedprivatekey" "extendedpublickey" "legacy" "privatekey" "schemes" "threshold" )
# shellcheck disable=SC2039
ALL_BLS_OBJ_FILES=$(printf "%s.o " "${BLS_FILES[@]}")
PLATFORM=$1
ARCH=$2
PFX=${PLATFORM}-${ARCH}
SDK=$(xcrun --sdk "$PLATFORM" --show-sdk-path)
BUILDDIR=${BUILD}/bls-"${PFX}"
rm -rf "$BUILDDIR"
mkdir "$BUILDDIR"
# shellcheck disable=SC2039,SC2164
pushd "$BUILDDIR"
EXTRA_ARGS="$(version_min_flag "$PLATFORM")"
CURRENT_DIR=$(pwd)
# shellcheck disable=SC2039
for F in "${BLS_FILES[@]}"
do
clang -I"../contrib/relic/include" \
-I"../relic-${PFX}/_deps/relic-build/include" \
-I"../../src/" \
-I"../gmplib-${PFX}/include" \
-x c++ -std=c++14 -stdlib=libc++ -fembed-bitcode -arch "${ARCH}" -isysroot "${SDK}" "${EXTRA_ARGS}" \
-c "../../src/${F}.cpp" -o "${F}.o"
done
# shellcheck disable=SC2086
xcrun -sdk "$PLATFORM" ar -cvq libbls.a $ALL_BLS_OBJ_FILES
# shellcheck disable=SC2039,SC2164
popd # "$BUILDDIR"
}
build_all_arch() {
PLATFORM=$1
ARCH=$2
build_gmp_arch "$PLATFORM" "$ARCH"
build_relic_arch "$PLATFORM" "$ARCH"
build_bls_arch "$PLATFORM" "$ARCH"
}
build_target() {
BUILD_IN=$1
echo "Build target: $BUILD_IN"
ARCH=""
PLATFORM=""
# shellcheck disable=SC2039
if [[ $BUILD_IN = "x86_64-apple-ios" ]]; then
ARCH=x86_64
PLATFORM=$IPHONESIMULATOR
elif [[ $BUILD_IN = "aarch64-apple-ios" ]]; then
ARCH=arm64
PLATFORM=$IPHONEOS
elif [[ $BUILD_IN = "aarch64-apple-ios-sim" ]]; then
ARCH=arm64
PLATFORM=$IPHONESIMULATOR
elif [[ $BUILD_IN = "x86_64-apple-darwin" ]]; then
ARCH=x86_64
PLATFORM=$MACOS
elif [[ $BUILD_IN = "aarch64-apple-darwin" ]]; then
ARCH=arm64
PLATFORM=$MACOS
fi
build_all_arch "$PLATFORM" "$ARCH"
PFX="${PLATFORM}"-"${ARCH}"
rm -rf "build/artefacts/${BUILD_IN}"
mkdir -p "build/artefacts/${BUILD_IN}/include"
# libtool -static -o "build/artefacts/${BUILD_IN}/libbls.a" \
# "build/gmplib-${PFX}/lib/libgmp.a" \
# "build/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" \
# "build/bls-${PFX}/libbls.a"
cp "build/gmplib-${PFX}/lib/libgmp.a" "build/artefacts/${BUILD_IN}"
cp "build/relic-${PFX}/_deps/relic-build/lib/librelic_s.a" "build/artefacts/${BUILD_IN}"
cp "build/relic-${PFX}/_deps/sodium-build/libsodium.a" "build/artefacts/${BUILD_IN}"
cp "build/bls-${PFX}/libbls.a" "build/artefacts/${BUILD_IN}"
cp -rf build/bls-"${PFX}"/*.o build/artefacts/"${BUILD_IN}"/include
cp -rf src/*.hpp build/artefacts/"${BUILD_IN}"/include
cp -rf build/gmplib-"${PFX}"/include/gmp.h build/artefacts/"${BUILD_IN}"/include
cp -rf build/relic-"${PFX}"/_deps/relic-build/include/*.h build/artefacts/"${BUILD_IN}"/include
}
#make_relic_headers_universal() {
# RELIC_TARGET_DIR=relic-iphoneos-arm64
# perl -p -e 's/#define WSIZE.*/#ifdef __LP64__\n#define WSIZE 64\n#else\n#define WSIZE 32\n#endif/' \
# "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h" \
# > "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new"
#
# rm "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h"
# mv "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h.new" "build/contrib/relic/${RELIC_TARGET_DIR}/include/relic_conf.h"
#}
#
#copy_headers() {
## mkdir build/artefacts/include
# # Copy all headers we will need
# cp -rf src/*.hpp ${BUILD}/artefacts/include
# cp -rf ${BUILD}/contrib/gmp/include/gmp.h ${BUILD}/artefacts/include
# cp -rf ${BUILD}/contrib/relic/include/*.h ${BUILD}/artefacts/include
# cp -rf ${BUILD}/contrib/relic/include/low/*.h ${BUILD}/artefacts/include
# #cp -rf ${BUILD}/contrib/relic/relic-iphoneos-arm64/include/*.h ${BUILD}/artefacts/include
# rm -rf ${BUILD}/artefacts/include/test-utils.hpp
#}
prepare
build_target "$TARGET"
#copy_headers
#build_all "${MACOS};x86_64+arm64"
#build_all "${IPHONEOS};arm64|${IPHONESIMULATOR};arm64+x86_64"
#make_relic_headers_universal
#copy_headers
#make_fat_binary

View File

@ -1,5 +1,5 @@
AC_PREREQ([2.60])
AC_INIT([libdashbls],[1.2.4])
AC_INIT([libdashbls],[1.3.0])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([build-aux/m4])
@ -783,3 +783,4 @@ AC_OUTPUT
dnl Peplace conflict-prone PACKAGE-prefixed macros with DASHBLS
sed -i.old 's/PACKAGE/DASHBLS/g' depends/relic/include/relic_conf.h
sed -i.old 's/PACKAGE/DASHBLS/g' config.status

View File

@ -59,6 +59,7 @@ public:
GTElement Pair(const G2Element &b) const;
uint32_t GetFingerprint(bool fLegacy = false) const;
std::vector<uint8_t> Serialize(bool fLegacy = false) const;
G1Element Copy();
friend bool operator==(const G1Element &a, const G1Element &b);
friend bool operator!=(const G1Element &a, const G1Element &b);
@ -101,6 +102,7 @@ public:
G2Element Negate() const;
GTElement Pair(const G1Element &a) const;
std::vector<uint8_t> Serialize(bool fLegacy = false) const;
G2Element Copy();
friend bool operator==(G2Element const &a, G2Element const &b);
friend bool operator!=(G2Element const &a, G2Element const &b);

View File

@ -39,6 +39,7 @@ class CoreMPL {
public:
CoreMPL() = delete;
CoreMPL(const std::string& strId) : strCiphersuiteId(strId) {}
virtual ~CoreMPL() {}
// Generates a private key from a seed, similar to HD key generation
// (hashes the seed), and reduces it mod the group order
virtual PrivateKey KeyGen(const vector<uint8_t>& seed);
@ -112,7 +113,7 @@ protected:
bool fLegacy);
};
class BasicSchemeMPL : public CoreMPL {
class BasicSchemeMPL final : public CoreMPL {
public:
static const std::string CIPHERSUITE_ID;
BasicSchemeMPL() : CoreMPL(BasicSchemeMPL::CIPHERSUITE_ID) {}
@ -133,7 +134,7 @@ public:
const G2Element& signature) override;
};
class AugSchemeMPL : public CoreMPL {
class AugSchemeMPL final : public CoreMPL {
public:
static const std::string CIPHERSUITE_ID;
@ -186,7 +187,7 @@ public:
const G2Element& signature) override;
};
class PopSchemeMPL : public CoreMPL {
class PopSchemeMPL final : public CoreMPL {
public:
static const std::string CIPHERSUITE_ID;
@ -221,7 +222,7 @@ public:
/**
* This scheme reflects the Sign/Verify behaviour of older bls-signatures library versions (<0.1.29).
*/
class LegacySchemeMPL : public CoreMPL {
class LegacySchemeMPL final : public CoreMPL {
public:
LegacySchemeMPL() : CoreMPL(std::string{}) {}

View File

@ -34,5 +34,5 @@ foreach(file ${JS_BINDINGS_TESTS})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/${file} tests/${file} COPYONLY)
endforeach()
set_target_properties(blsjstmp PROPERTIES LINK_FLAGS "--bind -Oz --closure 1 -s MODULARIZE=1 -s NODEJS_CATCH_EXIT=1 -s NODEJS_CATCH_REJECTION=1")
set_target_properties(blsjstmp PROPERTIES LINK_FLAGS "--bind -Oz --closure 1 -s MODULARIZE=1")
add_custom_command(TARGET blsjstmp POST_BUILD COMMAND npm run build:web)

View File

@ -21,6 +21,7 @@ export declare class BasicSchemeMPL {
static deriveChildSk(sk: PrivateKey, index: number): PrivateKey;
static deriveChildSkUnhardened(sk: PrivateKey, index: number): PrivateKey;
static deriveChildPkUnhardened(pk: G1Element, index: number): G1Element;
static verifySecure(pk: G1Element, sig: G2Element, msg: Uint8Array): boolean;
}
export declare class PopSchemeMPL {

View File

@ -42,7 +42,8 @@ EMSCRIPTEN_BINDINGS(blsjs) {
.class_function("aggregateVerify", &SchemeMPLWrapper<BasicSchemeMPL>::AggregateVerify)
.class_function("deriveChildSk", &SchemeMPLWrapper<BasicSchemeMPL>::DeriveChildSk)
.class_function("deriveChildSkUnhardened", &SchemeMPLWrapper<BasicSchemeMPL>::DeriveChildSkUnhardened)
.class_function("deriveChildPkUnhardened", &SchemeMPLWrapper<BasicSchemeMPL>::DeriveChildPkUnhardened);
.class_function("deriveChildPkUnhardened", &SchemeMPLWrapper<BasicSchemeMPL>::DeriveChildPkUnhardened)
.class_function("verifySecure", &SchemeMPLWrapper<BasicSchemeMPL>::VerifySecure);
class_<PopSchemeMPLWrapper>("PopSchemeMPL")
.class_function("skToG1", &PopSchemeMPLWrapper::SkToG1)

View File

@ -81,6 +81,15 @@ template <typename SchemeMPL> class SchemeMPLWrapper : public JSWrapper<SchemeMP
return G1ElementWrapper(mpl.DeriveChildPkUnhardened(pk.GetWrappedInstance(), index));
}
static bool VerifySecure(val pubkeyArray, const G2ElementWrapper &signature, val messageVal) {
std::vector<G1Element> pubkeys = G1ElementWrapper::Unwrap
(helpers::toVectorFromJSArray<G1ElementWrapper>(pubkeyArray));
std::vector <uint8_t> message = helpers::toVector(messageVal);
return mpl.VerifySecure(pubkeys, signature.GetWrappedInstance(), message);
}
protected:
static inline SchemeMPL mpl;
};

View File

@ -21,6 +21,7 @@ from bls12381 import h_eff, q
from ec import JacobianPoint, default_ec_twist, eval_iso
from fields import Fq, Fq2, roots_of_unity
from hash_to_field import Hp2
from typing import Union
def sgn0(x: Fq2) -> int:
@ -198,7 +199,7 @@ def iso3(P):
#
# map from Fq2 element(s) to point in G2 subgroup of Ell2
#
def opt_swu2_map(t: Fq2, t2: Fq2 = None) -> JacobianPoint:
def opt_swu2_map(t: Fq2, t2: Union[Fq2, None] = None) -> JacobianPoint:
Pp = iso3(osswu2_help(t))
if t2 is not None:
Pp2 = iso3(osswu2_help(t2))

2
src/dashbls/rust-bindings/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Cargo.lock
target

View File

@ -0,0 +1,17 @@
unstable_features = true
blank_lines_lower_bound = 0
condense_wildcard_suffixes = true
error_on_line_overflow = true
error_on_unformatted = true
format_code_in_doc_comments = true
format_macro_matchers = true
format_strings = true
imports_granularity = "Crate"
normalize_comments = true
normalize_doc_attributes = true
reorder_impl_items = true
group_imports = "StdExternalCrate"
use_field_init_shorthand = true
use_try_shorthand = true
wrap_comments = true

View File

@ -0,0 +1,15 @@
[package]
name = "bls-dash-sys"
description = ""
version = "1.2.5"
build = "build.rs"
edition = "2021"
[features]
default = []
apple = []
[build-dependencies]
cc = "1.0"
bindgen = "0.65.1"
glob ="0.3"

View File

@ -0,0 +1,435 @@
pub type G1Element = *mut ::std::os::raw::c_void;
pub type G2Element = *mut ::std::os::raw::c_void;
pub type PrivateKey = *mut ::std::os::raw::c_void;
pub type CoreMPL = *mut ::std::os::raw::c_void;
pub type BasicSchemeMPL = CoreMPL;
pub type AugSchemeMPL = CoreMPL;
pub type PopSchemeMPL = CoreMPL;
pub type LegacySchemeMPL = CoreMPL;
pub type BIP32ExtendedPrivateKey = *mut ::std::os::raw::c_void;
pub type BIP32ExtendedPublicKey = *mut ::std::os::raw::c_void;
pub type BIP32ChainCode = *mut ::std::os::raw::c_void;
extern "C" {
pub fn G1ElementSize() -> ::std::os::raw::c_int;
pub fn G1ElementFromBytes(
data: *const ::std::os::raw::c_void,
legacy: bool,
didErr: *mut bool,
) -> G1Element;
pub fn G1ElementGenerator() -> G1Element;
pub fn G1ElementIsValid(el: G1Element) -> bool;
pub fn G1ElementGetFingerprint(el: G1Element, legacy: bool) -> u32;
pub fn G1ElementIsEqual(el1: G1Element, el2: G1Element) -> bool;
pub fn G1ElementAdd(el1: G1Element, el2: G1Element) -> G1Element;
pub fn G1ElementMul(el: G1Element, sk: PrivateKey) -> G1Element;
pub fn G1ElementNegate(el: G1Element) -> G1Element;
pub fn G1ElementCopy(el: G1Element) -> G1Element;
pub fn G1ElementSerialize(el: G1Element, legacy: bool) -> *mut ::std::os::raw::c_void;
pub fn G1ElementFree(el: G1Element);
pub fn G2ElementSize() -> ::std::os::raw::c_int;
pub fn G2ElementFromBytes(
data: *const ::std::os::raw::c_void,
legacy: bool,
didErr: *mut bool,
) -> G2Element;
pub fn G2ElementGenerator() -> G2Element;
pub fn G2ElementIsValid(el: G2Element) -> bool;
pub fn G2ElementIsEqual(el1: G2Element, el2: G2Element) -> bool;
pub fn G2ElementAdd(el1: G2Element, el2: G2Element) -> G2Element;
pub fn G2ElementMul(el: G2Element, sk: PrivateKey) -> G2Element;
pub fn G2ElementNegate(el: G2Element) -> G2Element;
pub fn G2ElementCopy(el: G2Element) -> G2Element;
pub fn G2ElementSerialize(el: G2Element, legacy: bool) -> *mut ::std::os::raw::c_void;
pub fn G2ElementFree(el: G2Element);
pub fn PrivateKeyFromBytes(
data: *const ::std::os::raw::c_void,
modOrder: bool,
didErr: *mut bool,
) -> PrivateKey;
pub fn PrivateKeyFromSeedBIP32(data: *const ::std::os::raw::c_void, len: usize) -> PrivateKey;
pub fn PrivateKeyAggregate(sks: *mut *mut ::std::os::raw::c_void, len: usize) -> PrivateKey;
pub fn PrivateKeyGetG1Element(sk: PrivateKey, didErr: *mut bool) -> G1Element;
pub fn PrivateKeyGetG2Element(sk: PrivateKey, didErr: *mut bool) -> G2Element;
pub fn PrivateKeyGetG2Power(sk: PrivateKey, el: G2Element) -> G2Element;
pub fn PrivateKeyIsEqual(sk1: PrivateKey, sk2: PrivateKey) -> bool;
pub fn PrivateKeySerialize(sk: PrivateKey) -> *mut ::std::os::raw::c_void;
pub fn PrivateKeyFree(sk: PrivateKey);
pub fn PrivateKeySizeBytes() -> usize;
pub fn SecFree(p: *mut ::std::os::raw::c_void);
pub fn AllocPtrArray(len: usize) -> *mut *mut ::std::os::raw::c_void;
pub fn SetPtrArray(
arrPtr: *mut *mut ::std::os::raw::c_void,
elemPtr: *mut ::std::os::raw::c_void,
index: ::std::os::raw::c_int,
);
pub fn FreePtrArray(inPtr: *mut *mut ::std::os::raw::c_void);
pub fn GetPtrAtIndex(
arrPtr: *mut *mut ::std::os::raw::c_void,
index: ::std::os::raw::c_int,
) -> *mut ::std::os::raw::c_void;
pub fn SecAllocBytes(len: usize) -> *mut u8;
pub fn GetAddressAtIndex(
ptr: *mut u8,
index: ::std::os::raw::c_int,
) -> *mut ::std::os::raw::c_void;
pub fn GetLastErrorMsg() -> *const ::std::os::raw::c_char;
pub fn CoreMPLKeyGen(
scheme: CoreMPL,
seed: *const ::std::os::raw::c_void,
seedLen: usize,
didErr: *mut bool,
) -> PrivateKey;
pub fn CoreMPLSkToG1(scheme: CoreMPL, sk: PrivateKey) -> G1Element;
pub fn CoreMPLSign(
scheme: CoreMPL,
sk: PrivateKey,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
) -> G2Element;
pub fn CoreMPLVerify(
scheme: BasicSchemeMPL,
pk: G1Element,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
sig: G2Element,
) -> bool;
pub fn CoreMPLVerifySecure(
scheme: CoreMPL,
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
sig: G2Element,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
) -> bool;
pub fn CoreMPLAggregatePubKeys(
scheme: CoreMPL,
pubKeys: *mut *mut ::std::os::raw::c_void,
pkLen: usize,
) -> G1Element;
pub fn CoreMPLAggregateSigs(
scheme: CoreMPL,
sigs: *mut *mut ::std::os::raw::c_void,
sigLen: usize,
) -> G2Element;
pub fn CoreMPLDeriveChildSk(scheme: CoreMPL, sk: PrivateKey, index: u32) -> PrivateKey;
pub fn CoreMPLDeriveChildSkUnhardened(
scheme: CoreMPL,
sk: PrivateKey,
index: u32,
) -> PrivateKey;
pub fn CoreMPLDeriveChildPkUnhardened(scheme: CoreMPL, sk: G1Element, index: u32) -> G1Element;
pub fn CoreMPLAggregateVerify(
scheme: CoreMPL,
pks: *mut *mut ::std::os::raw::c_void,
pkLen: usize,
msgs: *mut *mut ::std::os::raw::c_void,
msgLens: *const ::std::os::raw::c_void,
msgLen: usize,
sig: G2Element,
) -> bool;
pub fn NewBasicSchemeMPL() -> BasicSchemeMPL;
pub fn BasicSchemeMPLAggregateVerify(
scheme: BasicSchemeMPL,
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
msgs: *mut *mut ::std::os::raw::c_void,
msgsLens: *const ::std::os::raw::c_void,
msgsLen: usize,
sig: G2Element,
) -> bool;
pub fn BasicSchemeMPLFree(scheme: BasicSchemeMPL);
pub fn NewAugSchemeMPL() -> AugSchemeMPL;
pub fn AugSchemeMPLSign(
scheme: AugSchemeMPL,
sk: PrivateKey,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
) -> G2Element;
pub fn AugSchemeMPLSignPrepend(
scheme: AugSchemeMPL,
sk: PrivateKey,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
prepPk: G1Element,
) -> G2Element;
pub fn AugSchemeMPLVerify(
scheme: AugSchemeMPL,
pk: G1Element,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
sig: G2Element,
) -> bool;
pub fn AugSchemeMPLAggregateVerify(
scheme: AugSchemeMPL,
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
msgs: *mut *mut ::std::os::raw::c_void,
msgsLens: *const ::std::os::raw::c_void,
msgsLen: usize,
sig: G2Element,
) -> bool;
pub fn AugSchemeMPLFree(scheme: AugSchemeMPL);
pub fn NewPopSchemeMPL() -> PopSchemeMPL;
pub fn PopSchemeMPLPopProve(scheme: PopSchemeMPL, sk: PrivateKey) -> G2Element;
pub fn PopSchemeMPLPopVerify(scheme: PopSchemeMPL, pk: G1Element, sig: G2Element) -> bool;
pub fn PopSchemeMPLFastAggregateVerify(
scheme: PopSchemeMPL,
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
msgs: *const ::std::os::raw::c_void,
msgsLen: usize,
sig: G2Element,
) -> bool;
pub fn PopSchemeMPLFree(scheme: PopSchemeMPL);
pub fn NewLegacySchemeMPL() -> LegacySchemeMPL;
pub fn LegacySchemeMPLSign(
scheme: LegacySchemeMPL,
sk: PrivateKey,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
) -> G2Element;
pub fn LegacySchemeMPLSignPrepend(
scheme: LegacySchemeMPL,
sk: PrivateKey,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
prepPk: G1Element,
) -> G2Element;
pub fn LegacySchemeMPLVerify(
scheme: LegacySchemeMPL,
pk: G1Element,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
sig: G2Element,
) -> bool;
pub fn LegacySchemeMPLVerifySecure(
scheme: LegacySchemeMPL,
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
sig: G2Element,
msg: *const ::std::os::raw::c_void,
msgLen: usize,
) -> bool;
pub fn LegacySchemeMPLAggregateVerify(
scheme: LegacySchemeMPL,
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
msgs: *mut *mut ::std::os::raw::c_void,
msgsLens: *const ::std::os::raw::c_void,
msgsLen: usize,
sig: G2Element,
) -> bool;
pub fn LegacySchemeMPLFree(scheme: LegacySchemeMPL);
pub fn ThresholdPrivateKeyShare(
sks: *mut *mut ::std::os::raw::c_void,
sksLen: usize,
hash: *const ::std::os::raw::c_void,
didErr: *mut bool,
) -> PrivateKey;
pub fn ThresholdPrivateKeyRecover(
sks: *mut *mut ::std::os::raw::c_void,
sksLen: usize,
hashes: *mut *mut ::std::os::raw::c_void,
hashesLen: usize,
didErr: *mut bool,
) -> PrivateKey;
pub fn ThresholdPublicKeyShare(
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
hash: *const ::std::os::raw::c_void,
didErr: *mut bool,
) -> G1Element;
pub fn ThresholdPublicKeyRecover(
pks: *mut *mut ::std::os::raw::c_void,
pksLen: usize,
hashes: *mut *mut ::std::os::raw::c_void,
hashesLen: usize,
didErr: *mut bool,
) -> G1Element;
pub fn ThresholdSignatureShare(
sigs: *mut *mut ::std::os::raw::c_void,
sigsLen: usize,
hash: *const ::std::os::raw::c_void,
didErr: *mut bool,
) -> G2Element;
pub fn ThresholdSignatureRecover(
sigs: *mut *mut ::std::os::raw::c_void,
sigsLen: usize,
hashes: *mut *mut ::std::os::raw::c_void,
hashesLen: usize,
didErr: *mut bool,
) -> G2Element;
pub fn ThresholdSign(sk: PrivateKey, hash: *const ::std::os::raw::c_void) -> G2Element;
pub fn ThresholdVerify(
pk: G1Element,
hash: *const ::std::os::raw::c_void,
sig: G2Element,
) -> bool;
pub fn BIP32ChainCodeSerialize(cc: BIP32ChainCode) -> *mut ::std::os::raw::c_void;
pub fn BIP32ChainCodeIsEqual(cc1: BIP32ChainCode, cc2: BIP32ChainCode) -> bool;
pub fn BIP32ChainCodeFree(cc: BIP32ChainCode);
pub fn BIP32ExtendedPublicKeyFromBytes(
data: *const ::std::os::raw::c_void,
legacy: bool,
didErr: *mut bool,
) -> BIP32ExtendedPublicKey;
pub fn BIP32ExtendedPublicKeyPublicChild(
pk: BIP32ExtendedPublicKey,
index: u32,
legacy: bool,
) -> BIP32ExtendedPublicKey;
pub fn BIP32ExtendedPublicKeyGetChainCode(pk: BIP32ExtendedPublicKey) -> BIP32ChainCode;
pub fn BIP32ExtendedPublicKeySerialize(
pk: BIP32ExtendedPublicKey,
legacy: bool,
) -> *mut ::std::os::raw::c_void;
pub fn BIP32ExtendedPublicKeyIsEqual(
pk1: BIP32ExtendedPublicKey,
pk2: BIP32ExtendedPublicKey,
) -> bool;
pub fn BIP32ExtendedPublicKeyGetPublicKey(
pk: BIP32ExtendedPublicKey,
) -> *mut ::std::os::raw::c_void;
pub fn BIP32ExtendedPublicKeyFree(pk: BIP32ExtendedPublicKey);
pub fn BIP32ExtendedPrivateKeyFromBytes(
data: *const ::std::os::raw::c_void,
didErr: *mut bool,
) -> BIP32ExtendedPrivateKey;
pub fn BIP32ExtendedPrivateKeyFromSeed(
data: *const ::std::os::raw::c_void,
len: usize,
didErr: *mut bool,
) -> BIP32ExtendedPrivateKey;
pub fn BIP32ExtendedPrivateKeyPrivateChild(
sk: BIP32ExtendedPrivateKey,
index: u32,
legacy: bool,
) -> BIP32ExtendedPrivateKey;
pub fn BIP32ExtendedPrivateKeyPublicChild(
sk: BIP32ExtendedPrivateKey,
index: u32,
) -> BIP32ExtendedPublicKey;
pub fn BIP32ExtendedPrivateKeyGetChainCode(sk: BIP32ExtendedPrivateKey) -> BIP32ChainCode;
pub fn BIP32ExtendedPrivateKeySerialize(
sk: BIP32ExtendedPrivateKey,
) -> *mut ::std::os::raw::c_void;
pub fn BIP32ExtendedPrivateKeyIsEqual(
sk1: BIP32ExtendedPrivateKey,
sk2: BIP32ExtendedPrivateKey,
) -> bool;
pub fn BIP32ExtendedPrivateKeyGetPrivateKey(
sk: BIP32ExtendedPrivateKey,
) -> *mut ::std::os::raw::c_void;
pub fn BIP32ExtendedPrivateKeyGetExtendedPublicKey(
sk: BIP32ExtendedPrivateKey,
legacy: bool,
didErr: *mut bool,
) -> BIP32ExtendedPublicKey;
pub fn BIP32ExtendedPrivateKeyGetPublicKey(
sk: BIP32ExtendedPrivateKey,
didErr: *mut bool,
) -> *mut ::std::os::raw::c_void;
pub fn BIP32ExtendedPrivateKeyFree(sk: BIP32ExtendedPrivateKey);
}

View File

@ -0,0 +1,374 @@
use std::{env, fs, io, io::Write, path::{Path, PathBuf}, process::{Command, Output}};
#[cfg(not(feature = "apple"))]
fn create_cross_cmake_command() -> Command {
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
let mut command = if target_arch.eq("wasm32") {
Command::new("emcmake")
} else {
Command::new("cmake")
};
if target_arch.eq("wasm32") {
command.arg("cmake");
}
command
}
fn handle_command_output(output: Output) {
io::stdout()
.write_all(&output.stdout)
.expect("should write output");
io::stderr()
.write_all(&output.stderr)
.expect("should write output");
assert!(output.status.success());
}
#[cfg(not(feature = "apple"))]
fn main() {
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
// TODO: fix build for wasm32 on MacOS
// errors with `error: linking with `rust-lld` failed: exit status: 1`
if target_arch.eq("wasm32") {
println!("Build for wasm32 is not fully supported");
return;
}
let root_path = Path::new("../..")
.canonicalize()
.expect("can't get abs path");
let bls_dash_build_path = root_path.join("build");
let bls_dash_src_path = root_path.join("src");
let c_bindings_path = root_path.join("rust-bindings/bls-dash-sys/c-bindings");
println!("root {}", root_path.display());
println!("bls_dash_build_path {}", bls_dash_build_path.display());
println!("bls_dash_src_path {}", bls_dash_src_path.display());
// println!("c_bindings_path {}", c_bindings_path.display());
// Run cmake
println!("Run cmake:");
if bls_dash_build_path.exists() {
fs::remove_dir_all(&bls_dash_build_path).expect("can't clean build directory");
}
fs::create_dir_all(&bls_dash_build_path).expect("can't create build directory");
let cmake_output = create_cross_cmake_command()
.current_dir(&bls_dash_build_path)
.arg("-DBUILD_BLS_PYTHON_BINDINGS=0")
.arg("-DBUILD_BLS_TESTS=0")
.arg("-DBUILD_BLS_BENCHMARKS=0")
.arg("-DBUILD_BLS_JS_BINDINGS=0")
.arg("..")
.output()
.expect("can't run cmake");
handle_command_output(cmake_output);
// Build deps for bls-signatures
println!("Build dependencies:");
let build_output = Command::new("cmake")
.args(["--build", ".", "--", "-j", "6"])
.current_dir(&bls_dash_build_path)
.output()
.expect("can't build bls-signatures deps");
handle_command_output(build_output);
// Collect include paths
let include_paths_file_path = bls_dash_build_path.join("include_paths.txt");
let include_paths =
fs::read_to_string(include_paths_file_path).expect("should read include paths from file");
let mut include_paths: Vec<_> = include_paths
.split(';')
.filter(|path| !path.is_empty())
.map(|path| PathBuf::from(path))
.collect();
include_paths.extend([
bls_dash_build_path.join("_deps/relic-src/include"),
bls_dash_build_path.join("_deps/relic-build/include"),
bls_dash_build_path.join("src"),
root_path.join("include/dashbls"),
bls_dash_build_path.join("depends/relic/include"),
bls_dash_build_path.join("depends/mimalloc/include"),
root_path.join("depends/relic/include"),
root_path.join("depends/mimalloc/include"),
bls_dash_src_path.clone(),
]);
// Build c binding
println!("Build C binding:");
let mut cc = cc::Build::new();
let cpp_files_mask = c_bindings_path.join("**/*.cpp");
let cpp_files: Vec<_> = glob::glob(cpp_files_mask.to_str().unwrap())
.expect("can't get list of cpp files")
.filter_map(Result::ok)
.collect();
cc.files(cpp_files)
.includes(&include_paths)
.cpp(true)
.flag_if_supported("-std=c++14");
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
// Fix homebrew LLVM installation issue
if env::consts::OS == "macos" && target_arch == "wasm32" {
cc.archiver("llvm-ar");
}
if target_arch.eq("wasm32") {
cc.flag_if_supported("-ffreestanding")
.define("_LIBCPP_HAS_NO_THREADS", Some("1"));
}
if !cfg!(debug_assertions) {
cc.opt_level(2);
}
cc.compile("bls-dash-sys");
// // Link dependencies
// println!(
// "cargo:rustc-link-search={}",
// bls_dash_build_path.join("_deps/sodium-build").display()
// );
// println!("cargo:rustc-link-lib=static=sodium");
println!(
"cargo:rustc-link-search={}",
root_path.join("build/depends/relic/lib").display()
);
println!("cargo:rustc-link-lib=static=relic_s");
println!(
"cargo:rustc-link-search={}",
root_path.join("build/depends/mimalloc").display()
);
println!("cargo:rustc-link-lib=static=mimalloc-secure");
println!(
"cargo:rustc-link-search={}",
bls_dash_build_path.join("src").display()
);
println!("cargo:rustc-link-lib=static=dashbls");
// Link GMP if exists
let gmp_libraries_file_path = bls_dash_build_path.join("gmp_libraries.txt");
if gmp_libraries_file_path.exists() {
let gmp_libraries_path = PathBuf::from(
fs::read_to_string(gmp_libraries_file_path)
.expect("should read gmp includes from file"),
);
let gmp_libraries_parent_path = gmp_libraries_path
.parent()
.expect("can't get gmp libraries parent dir");
println!(
"cargo:rustc-link-search={}",
gmp_libraries_parent_path.display()
);
println!("cargo:rustc-link-lib=static=gmp");
}
// Generate rust code for c binding to src/lib.rs
// println!("Generate C binding for rust:");
// let mut builder = bindgen::Builder::default()
// // .trust_clang_mangling(true)
// // .wasm_import_module_name()
// .size_t_is_usize(true)
// .parse_callbacks(Box::new(bindgen::CargoCallbacks));
// let headers_to_process = [
// "blschia.h",
// "elements.h",
// "privatekey.h",
// "schemes.h",
// "threshold.h",
// "bip32/chaincode.h",
// "bip32/extendedprivatekey.h",
// "bip32/extendedpublickey.h",
// ];
// for header in headers_to_process {
// builder = builder.header(c_bindings_path.join(header).to_str().unwrap())
// }
// if target_arch == "wasm32" {
// builder = builder.clang_args(
// include_paths
// .iter()
// .map(|path| format!("-I{}", path.display())),
// );
// }
// let bindings = builder.generate().expect("Unable to generate bindings");
// let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
// bindings
// .write_to_file(out_path.join("bindings.rs"))
// .expect("couldn't write bindings");
// // Rerun build if files changed
// println!("cargo:rerun-if-changed={}", c_bindings_path.display());
println!("cargo:rerun-if-changed={}", bls_dash_src_path.display());
}
// fn main() {
// let target = env::var("TARGET").unwrap();
// println!("Building bls-signatures for apple target: {}", target);
// let root_path = Path::new("../..")
// .canonicalize()
// .expect("can't get abs path");
// let bls_dash_build_path = root_path.join("build");
// let bls_dash_src_path = root_path.join("src");
// let artefacts_path = bls_dash_build_path.join("artefacts");
// let target_path = artefacts_path.join(&target);
// let script = root_path.join("apple.rust.single.sh");
// if bls_dash_build_path.exists() {
// fs::remove_dir_all(&bls_dash_build_path).expect("can't clean build directory");
// }
// fs::create_dir_all(&bls_dash_build_path).expect("can't create build directory");
// let output = Command::new("sh")
// .current_dir(&root_path)
// .arg(script)
// .arg(target)
// .output()
// .expect("Failed to execute the shell script");
// handle_command_output(output);
// let library_path = target_path.join("libbls.a");
// if !fs::metadata(&library_path).is_ok() {
// panic!("Library file not found: {}", library_path.display());
// }
// println!("cargo:rustc-link-search={}", target_path.display());
// println!("cargo:rustc-link-lib=static=gmp");
// println!("cargo:rustc-link-lib=static=sodium");
// println!("cargo:rustc-link-lib=static=relic_s");
// println!("cargo:rustc-link-search={}", bls_dash_build_path.join("src").display());
// println!("cargo:rustc-link-lib=static=bls");
// println!("cargo:rerun-if-changed={}", bls_dash_src_path.display());
// }
#[cfg(feature = "apple")]
fn main() {
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
// TODO: fix build for wasm32 on MacOS
// errors with `error: linking with `rust-lld` failed: exit status: 1`
if target_arch.eq("wasm32") {
println!("Build for wasm32 is not fully supported");
return;
}
let target = env::var("TARGET").unwrap();
println!("Building bls-signatures for apple target: {}", target);
let root_path = Path::new("../..")
.canonicalize()
.expect("can't get abs path");
let bls_dash_build_path = root_path.join("build");
let bls_dash_src_path = root_path.join("src");
let bls_dash_src_include_path = root_path.join("include/dashbls");
let c_bindings_path = root_path.join("rust-bindings/bls-dash-sys/c-bindings");
let artefacts_path = bls_dash_build_path.join("artefacts");
let target_path = artefacts_path.join(&target);
let script = root_path.join("apple.rust.deps.sh");
if bls_dash_build_path.exists() {
fs::remove_dir_all(&bls_dash_build_path).expect("can't clean build directory");
}
fs::create_dir_all(&bls_dash_build_path).expect("can't create build directory");
let output = Command::new("sh")
.current_dir(&root_path)
.arg(script)
.arg(target.as_str())
.output()
.expect("Failed to execute the shell script");
handle_command_output(output);
let (arch, platform) = match target.as_str() {
"x86_64-apple-ios" => ("x86_64", "iphonesimulator"),
"aarch64-apple-ios" => ("arm64", "iphoneos"),
"aarch64-apple-ios-sim" => ("arm64", "iphonesimulator"),
"x86_64-apple-darwin" => ("x86_64", "macosx"),
"aarch64-apple-darwin" => ("arm64", "macosx"),
_ => panic!("Target {} not supported", target.as_str())
};
env::set_var("IPHONEOS_DEPLOYMENT_TARGET", "13.0");
// Collect include paths
let include_paths_file_path = bls_dash_build_path.join("include_paths.txt");
let include_paths =
fs::read_to_string(include_paths_file_path).expect("should read include paths from file");
let mut include_paths: Vec<_> = include_paths
.split(';')
.filter(|path| !path.is_empty())
.map(|path| PathBuf::from(path))
.collect();
include_paths.extend([
bls_dash_build_path.join(format!("relic-{}-{}/_deps/relic-src/include", platform, arch)),
bls_dash_build_path.join(format!("relic-{}-{}/_deps/relic-build/include", platform, arch)),
bls_dash_build_path.join("contrib/relic/src"),
root_path.join("src"),
root_path.join("include/dashbls"),
root_path.join("depends/relic/include"),
root_path.join("depends/mimalloc/include"),
root_path.join("depends/catch2/include"),
bls_dash_src_path.clone(),
bls_dash_src_include_path.clone()
]);
let cpp_files: Vec<_> = glob::glob(c_bindings_path.join("**/*.cpp").to_str().unwrap())
.expect("can't get list of cpp files")
.filter_map(Result::ok)
.collect();
let mut cc = cc::Build::new();
cc.files(cpp_files)
.includes(&include_paths)
.cpp(true)
.flag("-Wno-unused-parameter")
.flag("-Wno-sign-compare")
.flag("-Wno-delete-non-abstract-non-virtual-dtor")
.flag("-std=c++14");
cc.compile("dashbls");
println!("cargo:rustc-link-search={}", target_path.display());
println!("cargo:rustc-link-lib=static=gmp");
// println!("cargo:rustc-link-lib=static=sodium");
// println!("cargo:rustc-link-lib=static=relic_s");
println!("cargo:rustc-link-lib=static=bls");
println!("cargo:rustc-link-search={}", bls_dash_src_path.display());
println!("cargo:rustc-link-lib=static=dashbls");
println!("cargo:rerun-if-changed={}", bls_dash_src_path.display());
}

View File

@ -0,0 +1,25 @@
#include <vector>
#include "bls.hpp"
#include "chaincode.h"
void* BIP32ChainCodeSerialize(const BIP32ChainCode cc)
{
const bls::ChainCode* ccPtr = (bls::ChainCode*)cc;
const std::vector<uint8_t> serialized = ccPtr->Serialize();
uint8_t* buffer = (uint8_t*)malloc(bls::ChainCode::SIZE);
memcpy(buffer, serialized.data(), bls::ChainCode::SIZE);
return (void*)buffer;
}
bool BIP32ChainCodeIsEqual(const BIP32ChainCode cc1, const BIP32ChainCode cc2)
{
const bls::ChainCode* cc1Ptr = (bls::ChainCode*)cc1;
const bls::ChainCode* cc2Ptr = (bls::ChainCode*)cc2;
return *cc1Ptr == *cc2Ptr;
}
void BIP32ChainCodeFree(const BIP32ChainCode cc)
{
const bls::ChainCode* ccPtr = (bls::ChainCode*)cc;
delete ccPtr;
}

View File

@ -0,0 +1,21 @@
#ifndef BIP32CHAINCODE_H_
#define BIP32CHAINCODE_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* BIP32ChainCode;
void* BIP32ChainCodeSerialize(const BIP32ChainCode cc);
bool BIP32ChainCodeIsEqual(const BIP32ChainCode cc1, const BIP32ChainCode cc2);
void BIP32ChainCodeFree(const BIP32ChainCode cc);
#ifdef __cplusplus
}
#endif
#endif // BIP32CHAINCODE_H_

View File

@ -0,0 +1,128 @@
#include "extendedprivatekey.h"
#include <vector>
#include "../blschia.h"
#include "../error.h"
#include "bls.hpp"
BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromBytes(const void* data, bool* didErr)
{
bls::ExtendedPrivateKey* el = nullptr;
try {
el = new bls::ExtendedPrivateKey(bls::ExtendedPrivateKey::FromBytes(
bls::Bytes((uint8_t*)(data), bls::ExtendedPrivateKey::SIZE)));
} catch (const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromSeed(const void* data, const size_t len, bool* didErr)
{
bls::ExtendedPrivateKey* el = nullptr;
try {
el = new bls::ExtendedPrivateKey(bls::ExtendedPrivateKey::FromSeed(
bls::Bytes((uint8_t*)(data), len)));
} catch (const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyPrivateChild(
const BIP32ExtendedPrivateKey sk,
const uint32_t index,
const bool legacy)
{
const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
return new bls::ExtendedPrivateKey(skPtr->PrivateChild(index, legacy));
}
BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyPublicChild(
const BIP32ExtendedPrivateKey sk,
const uint32_t index)
{
const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
return new bls::ExtendedPublicKey(skPtr->PublicChild(index));
}
BIP32ChainCode BIP32ExtendedPrivateKeyGetChainCode(const BIP32ExtendedPrivateKey sk)
{
const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
return new bls::ChainCode(skPtr->GetChainCode());
}
void* BIP32ExtendedPrivateKeySerialize(const BIP32ExtendedPrivateKey sk)
{
const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
uint8_t* buffer =
bls::Util::SecAlloc<uint8_t>(bls::ExtendedPrivateKey::SIZE);
skPtr->Serialize(buffer);
return (void*)buffer;
}
bool BIP32ExtendedPrivateKeyIsEqual(
const BIP32ExtendedPrivateKey sk1,
const BIP32ExtendedPrivateKey sk2)
{
const bls::ExtendedPrivateKey* sk1Ptr = (bls::ExtendedPrivateKey*)sk1;
const bls::ExtendedPrivateKey* sk2Ptr = (bls::ExtendedPrivateKey*)sk2;
return *sk1Ptr == *sk2Ptr;
}
void* BIP32ExtendedPrivateKeyGetPrivateKey(const BIP32ExtendedPrivateKey sk)
{
bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
return new bls::PrivateKey(skPtr->GetPrivateKey());
}
void* BIP32ExtendedPrivateKeyGetPublicKey(
const BIP32ExtendedPrivateKey sk,
bool* didErr)
{
bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
bls::G1Element* el = nullptr;
try {
el = new bls::G1Element(skPtr->GetPublicKey());
*didErr = false;
} catch (const std::exception& ex) {
// set err
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
return el;
}
BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyGetExtendedPublicKey(
const BIP32ExtendedPrivateKey sk,
const bool legacy,
bool* didErr)
{
bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
bls::ExtendedPublicKey* pk = nullptr;
try {
pk = new bls::ExtendedPublicKey(skPtr->GetExtendedPublicKey(legacy));
*didErr = false;
} catch (const std::exception& ex) {
// set err
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
return pk;
}
void BIP32ExtendedPrivateKeyFree(const BIP32ExtendedPrivateKey sk)
{
const bls::ExtendedPrivateKey* skPtr = (bls::ExtendedPrivateKey*)sk;
delete skPtr;
}

View File

@ -0,0 +1,48 @@
#ifndef BIP32EXTENDEDPRIVATEKEY_H_
#define BIP32EXTENDEDPRIVATEKEY_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "extendedpublickey.h"
#include "chaincode.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void* BIP32ExtendedPrivateKey;
// ExtendedPrivateKey
BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromBytes(
const void* data,
bool* didErr);
BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyFromSeed(const void* data, const size_t len, bool* didErr);
BIP32ExtendedPrivateKey BIP32ExtendedPrivateKeyPrivateChild(
const BIP32ExtendedPrivateKey sk,
const uint32_t index,
const bool legacy);
BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyPublicChild(
const BIP32ExtendedPrivateKey sk,
const uint32_t index);
BIP32ChainCode BIP32ExtendedPrivateKeyGetChainCode(const BIP32ExtendedPrivateKey sk);
void* BIP32ExtendedPrivateKeySerialize(const BIP32ExtendedPrivateKey sk);
bool BIP32ExtendedPrivateKeyIsEqual(
const BIP32ExtendedPrivateKey sk1,
const BIP32ExtendedPrivateKey sk2);
void* BIP32ExtendedPrivateKeyGetPrivateKey(const BIP32ExtendedPrivateKey sk);
BIP32ExtendedPublicKey BIP32ExtendedPrivateKeyGetExtendedPublicKey(
const BIP32ExtendedPrivateKey sk,
const bool legacy,
bool* didErr);
void* BIP32ExtendedPrivateKeyGetPublicKey(
const BIP32ExtendedPrivateKey sk,
bool* didErr);
void BIP32ExtendedPrivateKeyFree(const BIP32ExtendedPrivateKey sk);
#ifdef __cplusplus
}
#endif
#endif // BIP32EXTENDEDPRIVATEKEY_H_

View File

@ -0,0 +1,72 @@
#include "extendedpublickey.h"
#include <vector>
#include "../blschia.h"
#include "../error.h"
#include "bls.hpp"
BIP32ExtendedPublicKey BIP32ExtendedPublicKeyFromBytes(
const void* data,
const bool legacy,
bool* didErr)
{
bls::ExtendedPublicKey* el = nullptr;
try {
el = new bls::ExtendedPublicKey(bls::ExtendedPublicKey::FromBytes(
bls::Bytes((uint8_t*)(data), bls::ExtendedPublicKey::SIZE),
legacy));
} catch (const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
BIP32ExtendedPublicKey BIP32ExtendedPublicKeyPublicChild(
const BIP32ExtendedPublicKey pk,
const uint32_t index,
const bool legacy)
{
const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk;
return new bls::ExtendedPublicKey(pkPtr->PublicChild(index, legacy));
}
BIP32ChainCode BIP32ExtendedPublicKeyGetChainCode(const BIP32ExtendedPublicKey pk)
{
const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk;
return new bls::ChainCode(pkPtr->GetChainCode());
}
void* BIP32ExtendedPublicKeyGetPublicKey(const BIP32ExtendedPublicKey pk) {
bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk;
return new bls::G1Element(pkPtr->GetPublicKey());
}
void* BIP32ExtendedPublicKeySerialize(
const BIP32ExtendedPublicKey pk,
const bool legacy)
{
const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk;
const std::vector<uint8_t> serialized = pkPtr->Serialize(legacy);
uint8_t* buffer = (uint8_t*)malloc(bls::ExtendedPublicKey::SIZE);
memcpy(buffer, serialized.data(), bls::ExtendedPublicKey::SIZE);
return (void*)buffer;
}
bool BIP32ExtendedPublicKeyIsEqual(
const BIP32ExtendedPublicKey pk1,
const BIP32ExtendedPublicKey pk2)
{
const bls::ExtendedPublicKey* pk1Ptr = (bls::ExtendedPublicKey*)pk1;
const bls::ExtendedPublicKey* pk2Ptr = (bls::ExtendedPublicKey*)pk2;
return *pk1Ptr == *pk2Ptr;
}
void BIP32ExtendedPublicKeyFree(const BIP32ExtendedPublicKey pk)
{
const bls::ExtendedPublicKey* pkPtr = (bls::ExtendedPublicKey*)pk;
delete pkPtr;
}

View File

@ -0,0 +1,38 @@
#ifndef BIP32EXTENDEDPUBLICKEY_H_
#define BIP32EXTENDEDPUBLICKEY_H_
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "chaincode.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void* BIP32ExtendedPublicKey;
// ExtendedPublicKey
BIP32ExtendedPublicKey BIP32ExtendedPublicKeyFromBytes(
const void* data,
const bool legacy,
bool* didErr);
BIP32ExtendedPublicKey BIP32ExtendedPublicKeyPublicChild(
const BIP32ExtendedPublicKey pk,
const uint32_t index,
const bool legacy);
BIP32ChainCode BIP32ExtendedPublicKeyGetChainCode(const BIP32ExtendedPublicKey pk);
void* BIP32ExtendedPublicKeyGetPublicKey(const BIP32ExtendedPublicKey pk);
void* BIP32ExtendedPublicKeySerialize(
const BIP32ExtendedPublicKey pk,
const bool legacy);
bool BIP32ExtendedPublicKeyIsEqual(
const BIP32ExtendedPublicKey pk1,
const BIP32ExtendedPublicKey pk2);
void BIP32ExtendedPublicKeyFree(const BIP32ExtendedPublicKey pk);
#ifdef __cplusplus
}
#endif
#endif // BIP32EXTENDEDPUBLICKEY_H_

View File

@ -0,0 +1,56 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string>
#include <stdlib.h>
#include "bls.hpp"
#include "error.h"
#include "blschia.h"
// TODO: Revisit
std::string gErrMsg;
void SecFree(void *p) {
bls::Util::SecFree(p);
}
void** AllocPtrArray(size_t len) {
// caller to free
return (void**)bls::Util::SecAlloc<uint8_t>(sizeof(void*) * len);
}
void SetPtrArray(void** arrPtr, void* elemPtr, int index) {
arrPtr[index] = elemPtr;
}
void FreePtrArray(void** inPtr) {
bls::Util::SecFree(inPtr);
}
void* GetPtrAtIndex(void** arrPtr, int index) {
return arrPtr[index];
}
uint8_t* SecAllocBytes(size_t len) {
return (uint8_t*)bls::Util::SecAlloc<uint8_t>(sizeof(uint8_t) * len);
}
void* GetAddressAtIndex(uint8_t* ptr, int index) {
return (void*)&ptr[index];
}
const char* GetLastErrorMsg() {
return gErrMsg.c_str();
}

View File

@ -0,0 +1,46 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef BLSCHIA_H_
#define BLSCHIA_H_
#include <stdbool.h>
#include <stdint.h>
#include "privatekey.h"
#ifdef __cplusplus
extern "C" {
#endif
// Export the BLS SecFree method
void SecFree(void *p);
typedef void** carr;
// Additional C++ helper funcs for allocations
void** AllocPtrArray(size_t len);
void SetPtrArray(void **arrPtr, void *elemPtr, int index);
void FreePtrArray(void **inPtr);
void* GetPtrAtIndex(void **arrPtr, int index);
// Allocates an array of bytes with size of passed in len argument
uint8_t* SecAllocBytes(size_t len);
void* GetAddressAtIndex(uint8_t *ptr, int index);
const char* GetLastErrorMsg();
#ifdef __cplusplus
}
#endif
#endif // BLSCHIA_H_

View File

@ -0,0 +1,162 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include "bls.hpp"
#include "blschia.h"
#include "error.h"
#include "elements.h"
// G1Element
int G1ElementSize() {
return bls::G1Element::SIZE;
}
G1Element G1ElementFromBytes(const void* data, bool legacy, bool* didErr) {
bls::G1Element* el = nullptr;
try {
el = new bls::G1Element(
bls::G1Element::FromBytes(bls::Bytes((uint8_t*)(data), bls::G1Element::SIZE), legacy)
);
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
G1Element G1ElementGenerator() {
return new bls::G1Element(bls::G1Element::Generator());
}
bool G1ElementIsValid(const G1Element el) {
const bls::G1Element* elPtr = (bls::G1Element*)el;
return elPtr->IsValid();
}
uint32_t G1ElementGetFingerprint(const G1Element el, const bool legacy) {
const bls::G1Element* elPtr = (bls::G1Element*)el;
return elPtr->GetFingerprint(legacy);
}
void* G1ElementSerialize(const G1Element el, const bool legacy) {
const bls::G1Element* elPtr = (bls::G1Element*)el;
const std::vector<uint8_t> serialized = elPtr->Serialize(legacy);
uint8_t* buffer = (uint8_t*)malloc(bls::G1Element::SIZE);
memcpy(buffer, serialized.data(), bls::G1Element::SIZE);
return (void*)buffer;
}
bool G1ElementIsEqual(const G1Element el1, const G1Element el2) {
const bls::G1Element* el1Ptr = (bls::G1Element*)el1;
const bls::G1Element* el2Ptr = (bls::G1Element*)el2;
return *el1Ptr == *el2Ptr;
}
G1Element G1ElementAdd(const G1Element el1, const G1Element el2) {
const bls::G1Element* el1Ptr = (bls::G1Element*)el1;
const bls::G1Element* el2Ptr = (bls::G1Element*)el2;
return new bls::G1Element((*el1Ptr) + (*el2Ptr));
}
G1Element G1ElementMul(const G1Element el, const PrivateKey sk) {
const bls::G1Element* elPtr = (bls::G1Element*)el;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G1Element(*elPtr * *skPtr);
}
G1Element G1ElementNegate(const G1Element el) {
const bls::G1Element* elPtr = (bls::G1Element*)el;
return new bls::G1Element(elPtr->Negate());
}
G1Element G1ElementCopy(const G1Element el) {
return new bls::G1Element(((bls::G1Element*)el)->Copy());
}
void G1ElementFree(const G1Element el) {
const bls::G1Element* elPtr = (bls::G1Element*)el;
delete elPtr;
}
// G2Element
int G2ElementSize() {
return bls::G2Element::SIZE;
}
G2Element G2ElementFromBytes(const void* data, const bool legacy, bool* didErr) {
bls::G2Element* el = nullptr;
try {
el = new bls::G2Element(
bls::G2Element::FromBytes(bls::Bytes((uint8_t*)data, bls::G2Element::SIZE), legacy)
);
*didErr = false;
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
return el;
}
G2Element G2ElementGenerator() {
return new bls::G2Element(bls::G2Element::Generator());
}
bool G2ElementIsValid(const G2Element el) {
const bls::G2Element* elPtr = (bls::G2Element*)el;
return elPtr->IsValid();
}
void* G2ElementSerialize(const G2Element el, const bool legacy) {
const bls::G2Element* elPtr = (bls::G2Element*)el;
const std::vector<uint8_t> serialized = elPtr->Serialize(legacy);
uint8_t* buffer = (uint8_t*)malloc(bls::G2Element::SIZE);
memcpy(buffer, serialized.data(), bls::G2Element::SIZE);
return (void*)buffer;
}
bool G2ElementIsEqual(const G2Element el1, const G2Element el2) {
const bls::G2Element* el1Ptr = (bls::G2Element*)el1;
const bls::G2Element* el2Ptr = (bls::G2Element*)el2;
return *el1Ptr == *el2Ptr;
}
G2Element G2ElementAdd(const G2Element el1, const G2Element el2) {
bls::G2Element* el1Ptr = (bls::G2Element*)el1;
bls::G2Element* el2Ptr = (bls::G2Element*)el2;
return new bls::G2Element(*el1Ptr + *el2Ptr);
}
G2Element G2ElementMul(const G2Element el, const PrivateKey sk) {
const bls::G2Element* elPtr = (bls::G2Element*)el;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(*elPtr * *skPtr);
}
G2Element G2ElementNegate(const G2Element el) {
const bls::G2Element* elPtr = (bls::G2Element*)el;
return new bls::G2Element(elPtr->Negate());
}
G2Element G2ElementCopy(const G1Element el) {
return new bls::G2Element(((bls::G2Element*)el)->Copy());
}
void G2ElementFree(const G2Element el) {
bls::G2Element* elPtr = (bls::G2Element*)el;
delete elPtr;
}

View File

@ -0,0 +1,58 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ELEMENTS_H_
#define ELEMENTS_H_
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* G1Element;
typedef void* G2Element;
typedef void* PrivateKey;
// G1Element
int G1ElementSize();
G1Element G1ElementFromBytes(const void* data, const bool legacy, bool* didErr);
G1Element G1ElementGenerator();
bool G1ElementIsValid(const G1Element el);
uint32_t G1ElementGetFingerprint(const G1Element el, const bool legacy);
bool G1ElementIsEqual(const G1Element el1, const G1Element el2);
G1Element G1ElementAdd(const G1Element el1, const G1Element el2);
G1Element G1ElementMul(const G1Element el, const PrivateKey sk);
G1Element G1ElementNegate(const G1Element el);
G1Element G1ElementCopy(const G1Element el);
void* G1ElementSerialize(const G1Element el, const bool legacy);
void G1ElementFree(const G1Element el);
// G2Element
int G2ElementSize();
G2Element G2ElementFromBytes(const void* data, const bool legacy, bool* didErr);
G2Element G2ElementGenerator();
bool G2ElementIsValid(const G2Element el);
bool G2ElementIsEqual(const G2Element el1, const G2Element el2);
G2Element G2ElementAdd(const G2Element el1, const G2Element el2);
G2Element G2ElementMul(const G2Element el, const PrivateKey sk);
G2Element G2ElementNegate(const G2Element el);
G2Element G2ElementCopy(const G2Element el);
void* G2ElementSerialize(const G2Element el, const bool legacy);
void G2ElementFree(const G2Element el);
#ifdef __cplusplus
}
#endif
#endif // ELEMENTS_H_

View File

@ -0,0 +1,21 @@
// Copyright (c) 2020 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ERROR_H_
#define ERROR_H_
#include <string>
extern std::string gErrMsg;
#endif // ERROR_H_

View File

@ -0,0 +1,120 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include "bls.hpp"
#include "privatekey.h"
#include "blschia.h"
#include "error.h"
#include "utils.hpp"
// private key bindings implementation
PrivateKey PrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr) {
bls::PrivateKey* skPtr = nullptr;
try {
skPtr = new bls::PrivateKey(
bls::PrivateKey::FromBytes(
bls::Bytes((uint8_t*)data, bls::PrivateKey::PRIVATE_KEY_SIZE),
modOrder
)
);
} catch (const std::exception& ex) {
// set err
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return skPtr;
}
PrivateKey PrivateKeyFromSeedBIP32(const void* data, const size_t len) {
return new bls::PrivateKey(
bls::PrivateKey::FromSeedBIP32(bls::Bytes((uint8_t*)data, len))
);
}
PrivateKey PrivateKeyAggregate(void** sks, const size_t len) {
return new bls::PrivateKey(
bls::PrivateKey::Aggregate(toBLSVector<bls::PrivateKey>(sks, len))
);
}
void* PrivateKeySerialize(const PrivateKey sk) {
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
uint8_t* buffer = bls::Util::SecAlloc<uint8_t>(bls::PrivateKey::PRIVATE_KEY_SIZE);
skPtr->Serialize(buffer);
return (void*)buffer;
}
size_t PrivateKeySizeBytes() {
return bls::PrivateKey::PRIVATE_KEY_SIZE;
}
bool PrivateKeyIsEqual(const PrivateKey sk1, const PrivateKey sk2) {
const bls::PrivateKey* sk1Ptr = (bls::PrivateKey*)sk1;
const bls::PrivateKey* sk2Ptr = (bls::PrivateKey*)sk2;
return *sk1Ptr == *sk2Ptr;
}
G1Element PrivateKeyGetG1Element(const PrivateKey sk, bool* didErr) {
bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
bls::G1Element* el = nullptr;
try {
el = new bls::G1Element(skPtr->GetG1Element());
*didErr = false;
} catch (const std::exception& ex) {
// set err
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
return el;
}
G2Element PrivateKeyGetG2Element(const PrivateKey sk, bool* didErr) {
bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
bls::G2Element* el = nullptr;
try {
el = new bls::G2Element(skPtr->GetG2Element());
*didErr = false;
} catch (const std::exception& ex) {
// set err
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
return el;
}
G2Element PrivateKeyGetG2Power(const PrivateKey sk, const G2Element el) {
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
const bls::G2Element* elPtr = (bls::G2Element*)el;
return new bls::G2Element(skPtr->GetG2Power(*elPtr));
}
G2Element PrivateKeySignG2(const PrivateKey sk,
uint8_t* msg,
const size_t len,
const uint8_t* dst,
const size_t dstLen) {
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(skPtr->SignG2(msg, len, dst, dstLen));
}
void PrivateKeyFree(PrivateKey sk) {
bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
delete skPtr;
}

View File

@ -0,0 +1,40 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef PRIVATEKEY_H_
#define PRIVATEKEY_H_
#include <stdbool.h>
#include <stdlib.h>
#include "elements.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void* PrivateKey;
PrivateKey PrivateKeyFromBytes(const void* data, const bool modOrder, bool* didErr);
PrivateKey PrivateKeyFromSeedBIP32(const void* data, const size_t len);
PrivateKey PrivateKeyAggregate(void** sks, const size_t len);
G1Element PrivateKeyGetG1Element(const PrivateKey sk, bool* didErr);
G2Element PrivateKeyGetG2Element(const PrivateKey sk, bool* didErr);
G2Element PrivateKeyGetG2Power(const PrivateKey sk, const G2Element el);
bool PrivateKeyIsEqual(const PrivateKey sk1, const PrivateKey sk2);
void* PrivateKeySerialize(const PrivateKey sk);
void PrivateKeyFree(const PrivateKey sk);
size_t PrivateKeySizeBytes();
#ifdef __cplusplus
}
#endif
#endif // PRIVATEKEY_H_

View File

@ -0,0 +1,388 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "schemes.h"
#include <vector>
#include "bls.hpp"
#include "blschia.h"
#include "elements.h"
#include "error.h"
#include "privatekey.h"
#include "utils.hpp"
// Implementation of bindings for CoreMPL class
PrivateKey CoreMPLKeyGen(
const CoreMPL scheme,
const void* seed,
const size_t seedLen,
bool* didErr)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
bls::PrivateKey* sk = nullptr;
try {
sk = new bls::PrivateKey(
schemePtr->KeyGen(bls::Bytes((uint8_t*)seed, seedLen)));
} catch (const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return sk;
}
G1Element CoreMPLSkToG1(const CoreMPL scheme, const PrivateKey sk)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G1Element(schemePtr->SkToG1(*skPtr));
}
G2Element CoreMPLSign(
CoreMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen)));
}
bool CoreMPLVerify(
const CoreMPL scheme,
const G1Element pk,
const void* msg,
const size_t msgLen,
const G2Element sig)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const bls::G1Element* pkPtr = (bls::G1Element*)pk;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
return schemePtr->Verify(
*pkPtr, bls::Bytes((uint8_t*)msg, msgLen), *sigPtr);
}
bool CoreMPLVerifySecure(
const CoreMPL scheme,
void** pks,
const size_t pksLen,
const G2Element sig,
const void* msg,
const size_t msgLen)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const std::vector<bls::G1Element> vecPubKeys =
toBLSVector<bls::G1Element>(pks, pksLen);
const uint8_t* msgPtr = (uint8_t*)msg;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
return schemePtr->VerifySecure(
vecPubKeys, *sigPtr, bls::Bytes(msgPtr, msgLen));
}
G1Element CoreMPLAggregatePubKeys(
const CoreMPL scheme,
void** pks,
const size_t pksLen)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
return new bls::G1Element(
schemePtr->Aggregate(toBLSVector<bls::G1Element>(pks, pksLen)));
}
G2Element CoreMPLAggregateSigs(
const CoreMPL scheme,
void** sigs,
const size_t sigsLen)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
return new bls::G2Element(
schemePtr->Aggregate(toBLSVector<bls::G2Element>(sigs, sigsLen)));
}
PrivateKey CoreMPLDeriveChildSk(
const CoreMPL scheme,
const PrivateKey sk,
const uint32_t index)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::PrivateKey(schemePtr->DeriveChildSk(*skPtr, index));
}
PrivateKey CoreMPLDeriveChildSkUnhardened(
CoreMPL scheme,
PrivateKey sk,
uint32_t index)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::PrivateKey(
schemePtr->DeriveChildSkUnhardened(*skPtr, index));
}
G1Element CoreMPLDeriveChildPkUnhardened(
CoreMPL scheme,
G1Element el,
uint32_t index)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
bls::G1Element* elPtr = (bls::G1Element*)el;
return new bls::G1Element(
schemePtr->DeriveChildPkUnhardened(*elPtr, index));
}
bool CoreMPLAggregateVerify(
const CoreMPL scheme,
void** pks,
const size_t pksLen,
void** msgs,
const void* msgsLens,
const size_t msgsLen,
const G2Element sig)
{
bls::CoreMPL* schemePtr = (bls::CoreMPL*)scheme;
const size_t* msgLensPtr = (size_t*)msgsLens;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
const std::vector<bls::G1Element> vecPubKeys =
toBLSVector<bls::G1Element>(pks, pksLen);
const std::vector<size_t> vecMsgsLens =
std::vector<size_t>(msgLensPtr, msgLensPtr + msgsLen);
const std::vector<bls::Bytes> vecMsgs =
toVectorBytes(msgs, msgsLen, vecMsgsLens);
return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr);
}
// BasicSchemeMPL
BasicSchemeMPL NewBasicSchemeMPL() { return new bls::BasicSchemeMPL(); }
bool BasicSchemeMPLAggregateVerify(
BasicSchemeMPL scheme,
void** pks,
const size_t pksLen,
void** msgs,
const void* msgsLens,
const size_t msgsLen,
const G2Element sig)
{
bls::BasicSchemeMPL* schemePtr = (bls::BasicSchemeMPL*)scheme;
const size_t* msgLensPtr = (size_t*)msgsLens;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
const std::vector<bls::G1Element> vecPubKeys =
toBLSVector<bls::G1Element>(pks, pksLen);
const std::vector<size_t> vecMsgsLens =
std::vector<size_t>(msgLensPtr, msgLensPtr + msgsLen);
const std::vector<bls::Bytes> vecMsgs =
toVectorBytes(msgs, msgsLen, vecMsgsLens);
return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr);
}
void BasicSchemeMPLFree(BasicSchemeMPL scheme)
{
bls::BasicSchemeMPL* schemePtr = (bls::BasicSchemeMPL*)scheme;
delete schemePtr;
}
// AugSchemeMPL
AugSchemeMPL NewAugSchemeMPL() { return new bls::AugSchemeMPL(); }
G2Element AugSchemeMPLSign(
const AugSchemeMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen)
{
bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen)));
}
G2Element AugSchemeMPLSignPrepend(
const AugSchemeMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen,
const G1Element prepPk)
{
bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
const bls::G1Element* prepPkPtr = (bls::G1Element*)prepPk;
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen), *prepPkPtr));
}
bool AugSchemeMPLVerify(
const AugSchemeMPL scheme,
const G1Element pk,
const void* msg,
const size_t msgLen,
const G2Element sig)
{
bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme;
const bls::G1Element* pkPtr = (bls::G1Element*)pk;
const uint8_t* msgPtr = (uint8_t*)msg;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
return schemePtr->Verify(*pkPtr, bls::Bytes(msgPtr, msgLen), *sigPtr);
}
bool AugSchemeMPLAggregateVerify(
const AugSchemeMPL scheme,
void** pks,
const size_t pksLen,
void** msgs,
const void* msgsLens,
const size_t msgsLen,
const G2Element sig)
{
bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme;
const size_t* msgLensPtr = (size_t*)msgsLens;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
const std::vector<bls::G1Element> vecPubKeys =
toBLSVector<bls::G1Element>(pks, pksLen);
const std::vector<size_t> vecMsgsLens =
std::vector<size_t>(msgLensPtr, msgLensPtr + msgsLen);
const std::vector<bls::Bytes> vecMsgs =
toVectorBytes(msgs, msgsLen, vecMsgsLens);
return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr);
}
void AugSchemeMPLFree(AugSchemeMPL scheme)
{
bls::AugSchemeMPL* schemePtr = (bls::AugSchemeMPL*)scheme;
delete schemePtr;
}
// PopSchemeMPL
PopSchemeMPL NewPopSchemeMPL() { return new bls::PopSchemeMPL(); }
G2Element PopSchemeMPLPopProve(
const PopSchemeMPL scheme,
const PrivateKey sk)
{
bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(schemePtr->PopProve(*skPtr));
}
bool PopSchemeMPLPopVerify(
const PopSchemeMPL scheme,
const G1Element pk,
const G2Element sig)
{
bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme;
const bls::G1Element* pkPtr = (bls::G1Element*)pk;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
return schemePtr->PopVerify(*pkPtr, *sigPtr);
}
bool PopSchemeMPLFastAggregateVerify(
const PopSchemeMPL scheme,
void** pks,
const size_t pksLen,
const void* msg,
const size_t msgLen,
const G2Element sig)
{
bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
const std::vector<bls::G1Element> vecPubKeys =
toBLSVector<bls::G1Element>(pks, pksLen);
return schemePtr->FastAggregateVerify(
vecPubKeys, bls::Bytes((uint8_t*)msg, msgLen), *sigPtr);
}
void PopSchemeMPLFree(PopSchemeMPL scheme)
{
bls::PopSchemeMPL* schemePtr = (bls::PopSchemeMPL*)scheme;
delete schemePtr;
}
// LegacySchemeMPL
LegacySchemeMPL NewLegacySchemeMPL() { return new bls::LegacySchemeMPL(); }
G2Element LegacySchemeMPLSign(
const LegacySchemeMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen)
{
bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme;
const bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(
schemePtr->Sign(*skPtr, bls::Bytes((uint8_t*)msg, msgLen)));
}
bool LegacySchemeMPLVerify(
const LegacySchemeMPL scheme,
const G1Element pk,
const void* msg,
const size_t msgLen,
const G2Element sig)
{
bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme;
const bls::G1Element* pkPtr = (bls::G1Element*)pk;
const uint8_t* msgPtr = (uint8_t*)msg;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
return schemePtr->Verify(*pkPtr, bls::Bytes(msgPtr, msgLen), *sigPtr);
}
bool LegacySchemeMPLVerifySecure(
const LegacySchemeMPL scheme,
void** pks,
const size_t pksLen,
const G2Element sig,
const void* msg,
const size_t msgLen)
{
bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme;
const std::vector<bls::G1Element> vecPubKeys =
toBLSVector<bls::G1Element>(pks, pksLen);
const uint8_t* msgPtr = (uint8_t*)msg;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
// Because of scheme pointer it will call CoreMPL::VerifySecure with 'legacy' flag variant
return schemePtr->VerifySecure(
vecPubKeys, *sigPtr, bls::Bytes(msgPtr, msgLen));
}
bool LegacySchemeMPLAggregateVerify(
const LegacySchemeMPL scheme,
void** pks,
const size_t pksLen,
void** msgs,
const void* msgsLens,
const size_t msgsLen,
const G2Element sig)
{
bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme;
const size_t* msgLensPtr = (size_t*)msgsLens;
const bls::G2Element* sigPtr = (bls::G2Element*)sig;
const std::vector<bls::G1Element> vecPubKeys =
toBLSVector<bls::G1Element>(pks, pksLen);
const std::vector<size_t> vecMsgsLens =
std::vector<size_t>(msgLensPtr, msgLensPtr + msgsLen);
const std::vector<bls::Bytes> vecMsgs =
toVectorBytes(msgs, msgsLen, vecMsgsLens);
return schemePtr->AggregateVerify(vecPubKeys, vecMsgs, *sigPtr);
}
void LegacySchemeMPLFree(LegacySchemeMPL scheme)
{
bls::LegacySchemeMPL* schemePtr = (bls::LegacySchemeMPL*)scheme;
delete schemePtr;
}

View File

@ -0,0 +1,184 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SCHEMES_H_
#define SCHEMES_H_
#include <stdbool.h>
#include <stdlib.h>
#include "elements.h"
#include "privatekey.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void* CoreMPL;
typedef CoreMPL BasicSchemeMPL;
typedef CoreMPL AugSchemeMPL;
typedef CoreMPL PopSchemeMPL;
typedef CoreMPL LegacySchemeMPL;
// CoreMPL
PrivateKey CoreMPLKeyGen(
const CoreMPL scheme,
const void* seed,
const size_t seedLen,
bool* didErr);
G1Element CoreMPLSkToG1(const CoreMPL scheme, const PrivateKey sk);
G2Element CoreMPLSign(
const CoreMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen);
bool CoreMPLVerify(
const BasicSchemeMPL scheme,
const G1Element pk,
const void* msg,
const size_t msgLen,
const G2Element sig);
bool CoreMPLVerifySecure(
const CoreMPL scheme,
void** pks,
const size_t pksLen,
const G2Element sig,
const void* msg,
const size_t msgLen);
G1Element CoreMPLAggregatePubKeys(
const CoreMPL scheme,
void** pubKeys,
const size_t pkLen);
G2Element CoreMPLAggregateSigs(
const CoreMPL scheme,
void** sigs,
const size_t sigLen);
PrivateKey CoreMPLDeriveChildSk(
const CoreMPL scheme,
const PrivateKey sk,
const uint32_t index);
PrivateKey CoreMPLDeriveChildSkUnhardened(
const CoreMPL scheme,
const PrivateKey sk,
const uint32_t index);
G1Element CoreMPLDeriveChildPkUnhardened(
const CoreMPL scheme,
const G1Element sk,
const uint32_t index);
bool CoreMPLAggregateVerify(
const CoreMPL scheme,
void** pks,
const size_t pkLen,
void** msgs,
const void* msgLens,
const size_t msgLen,
const G2Element sig);
// BasicSchemeMPL
BasicSchemeMPL NewBasicSchemeMPL();
bool BasicSchemeMPLAggregateVerify(
BasicSchemeMPL scheme,
void** pks,
const size_t pksLen,
void** msgs,
const void* msgsLens,
const size_t msgsLen,
const G2Element sig);
void BasicSchemeMPLFree(BasicSchemeMPL scheme);
// AugSchemeMPL
AugSchemeMPL NewAugSchemeMPL();
G2Element AugSchemeMPLSign(
const AugSchemeMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen);
G2Element AugSchemeMPLSignPrepend(
const AugSchemeMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen,
const G1Element prepPk);
bool AugSchemeMPLVerify(
const AugSchemeMPL scheme,
const G1Element pk,
const void* msg,
const size_t msgLen,
const G2Element sig);
bool AugSchemeMPLAggregateVerify(
const AugSchemeMPL scheme,
void** pks,
const size_t pksLen,
void** msgs,
const void* msgsLens,
const size_t msgsLen,
const G2Element sig);
void AugSchemeMPLFree(AugSchemeMPL scheme);
// PopSchemeMPL
PopSchemeMPL NewPopSchemeMPL();
G2Element PopSchemeMPLPopProve(
const PopSchemeMPL scheme,
const PrivateKey sk);
bool PopSchemeMPLPopVerify(
const PopSchemeMPL scheme,
const G1Element pk,
const G2Element sig);
bool PopSchemeMPLFastAggregateVerify(
const PopSchemeMPL scheme,
void** pks,
const size_t pksLen,
const void* msgs,
const size_t msgsLen,
const G2Element sig);
void PopSchemeMPLFree(PopSchemeMPL scheme);
// LegacySchemeMPL
LegacySchemeMPL NewLegacySchemeMPL();
G2Element LegacySchemeMPLSign(
const LegacySchemeMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen);
G2Element LegacySchemeMPLSignPrepend(
const LegacySchemeMPL scheme,
const PrivateKey sk,
const void* msg,
const size_t msgLen,
const G1Element prepPk);
bool LegacySchemeMPLVerify(
const LegacySchemeMPL scheme,
const G1Element pk,
const void* msg,
const size_t msgLen,
const G2Element sig);
bool LegacySchemeMPLVerifySecure(
const LegacySchemeMPL scheme,
void** pks,
const size_t pksLen,
const G2Element sig,
const void* msg,
const size_t msgLen);
bool LegacySchemeMPLAggregateVerify(
const LegacySchemeMPL scheme,
void** pks,
const size_t pksLen,
void** msgs,
const void* msgsLens,
const size_t msgsLen,
const G2Element sig);
void LegacySchemeMPLFree(LegacySchemeMPL scheme);
#ifdef __cplusplus
}
#endif
#endif // SCHEMES_H_

View File

@ -0,0 +1,168 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include <stdint.h>
#include "bls.hpp"
#include "privatekey.h"
#include "elements.h"
#include "blschia.h"
#include "threshold.h"
#include "utils.hpp"
#include "error.h"
std::vector<bls::Bytes> toVectorHashes(void** elems, const size_t len) {
std::vector<bls::Bytes> vec;
vec.reserve(len);
for (int i = 0 ; i < len; ++i) {
vec.push_back(
bls::Bytes((uint8_t*)elems[i], HashSize)
);
}
return vec;
}
PrivateKey ThresholdPrivateKeyShare(void** sks, const size_t sksLen, const void* hash, bool* didErr) {
bls::PrivateKey* sk = nullptr;
try {
sk = new bls::PrivateKey(
bls::Threshold::PrivateKeyShare(
toBLSVector<bls::PrivateKey>(sks, sksLen),
bls::Bytes((uint8_t*)hash, HashSize)
)
);
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return sk;
}
PrivateKey ThresholdPrivateKeyRecover(void** sks,
const size_t sksLen,
void** hashes,
const size_t hashesLen,
bool* didErr) {
bls::PrivateKey* sk = nullptr;
std::vector<bls::Bytes> pop = toVectorHashes(hashes, hashesLen);
try {
sk = new bls::PrivateKey(
bls::Threshold::PrivateKeyRecover(
toBLSVector<bls::PrivateKey>(sks, sksLen),
toVectorHashes(hashes, hashesLen)
)
);
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return sk;
}
G1Element ThresholdPublicKeyShare(void** pks, const size_t pksLen, const void* hash, bool* didErr) {
bls::G1Element* el = nullptr;
try {
el = new bls::G1Element(
bls::Threshold::PublicKeyShare(
toBLSVector<bls::G1Element>(pks, pksLen),
bls::Bytes((uint8_t*)hash, HashSize)
)
);
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
G1Element ThresholdPublicKeyRecover(void** pks,
const size_t pksLen,
void** hashes,
const size_t hashesLen,
bool* didErr) {
bls::G1Element* el = nullptr;
try {
el = new bls::G1Element(
bls::Threshold::PublicKeyRecover(
toBLSVector<bls::G1Element>(pks, pksLen),
toVectorHashes(hashes, hashesLen)
)
);
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
G2Element ThresholdSignatureShare(void** sigs, const size_t sigsLen, const void* hash, bool* didErr) {
bls::G2Element* el = nullptr;
try {
el = new bls::G2Element(
bls::Threshold::SignatureShare(
toBLSVector<bls::G2Element>(sigs, sigsLen),
bls::Bytes((uint8_t*)hash, HashSize)
)
);
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
G2Element ThresholdSignatureRecover(void** sigs,
const size_t sigsLen,
void** hashes,
const size_t hashesLen,
bool* didErr) {
bls::G2Element* el = nullptr;
try {
el = new bls::G2Element(
bls::Threshold::SignatureRecover(
toBLSVector<bls::G2Element>(sigs, sigsLen),
toVectorHashes(hashes, hashesLen)
)
);
} catch(const std::exception& ex) {
gErrMsg = ex.what();
*didErr = true;
return nullptr;
}
*didErr = false;
return el;
}
G2Element ThresholdSign(const PrivateKey sk, const void* hash) {
bls::PrivateKey* skPtr = (bls::PrivateKey*)sk;
return new bls::G2Element(
bls::Threshold::Sign(*skPtr, bls::Bytes((uint8_t*)hash, HashSize))
);
}
bool ThresholdVerify(const G1Element pk, const void* hash, const G2Element sig) {
bls::G1Element* pkPtr = (bls::G1Element*)pk;
bls::G2Element* sigPtr = (bls::G2Element*)sig;
return bls::Threshold::Verify(*pkPtr, bls::Bytes((uint8_t*)hash, HashSize), *sigPtr);
}

View File

@ -0,0 +1,55 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THRESHOLD_H_
#define THRESHOLD_H_
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "privatekey.h"
#include "elements.h"
#ifdef __cplusplus
extern "C" {
#endif
const int HashSize = 32;
PrivateKey ThresholdPrivateKeyShare(void** sks, const size_t sksLen, const void* hash, bool* didErr);
PrivateKey ThresholdPrivateKeyRecover(void** sks,
const size_t sksLen,
void** hashes,
const size_t hashesLen,
bool* didErr);
G1Element ThresholdPublicKeyShare(void** pks, const size_t pksLen, const void* hash, bool* didErr);
G1Element ThresholdPublicKeyRecover(void** pks,
const size_t pksLen,
void** hashes,
const size_t hashesLen,
bool* didErr);
G2Element ThresholdSignatureShare(void** sigs, const size_t sigsLen, const void* hash, bool* didErr);
G2Element ThresholdSignatureRecover(void** sigs,
const size_t sigsLen,
void** hashes,
const size_t hashesLen,
bool* didErr);
G2Element ThresholdSign(const PrivateKey sk, const void* hash);
bool ThresholdVerify(const G1Element pk, const void* hash, const G2Element sig);
#ifdef __cplusplus
}
#endif
#endif // THRESHOLD_H_

View File

@ -0,0 +1,40 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include "bls.hpp"
#include "privatekey.h"
#include "elements.h"
// helper functions
template <class T>
std::vector<T> toBLSVector(void** elems, const size_t len) {
std::vector<T> vec;
vec.reserve(len);
for (int i = 0 ; i < len; ++i) {
T* el = (T*)elems[i];
vec.push_back(*el);
}
return vec;
}
std::vector<bls::Bytes> toVectorBytes(void** elems, const size_t len, const std::vector<size_t> vecElemsLens) {
std::vector<bls::Bytes> vec;
vec.reserve(len);
for (int i = 0 ; i < len; ++i) {
uint8_t* elPtr = (uint8_t*)elems[i];
vec.push_back(bls::Bytes(elPtr, vecElemsLens[i]));
}
return vec;
}

View File

@ -0,0 +1,34 @@
// Copyright (c) 2021 The Dash Core developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <vector>
#include "bls.hpp"
#include "privatekey.h"
#include "elements.h"
// helper functions
template <class T>
std::vector<T> toBLSVector(void** elems, const size_t len) {
std::vector<T> vec;
vec.reserve(len);
for (int i = 0 ; i < (int)len; ++i) {
const T* el = (T*)elems[i];
vec.push_back(*el);
}
return vec;
}
std::vector<bls::Bytes> toVectorBytes(void** elems, const size_t len, const std::vector<size_t> vecElemsLens);

View File

@ -0,0 +1,8 @@
#include "c-bindings/blschia.h"
#include "c-bindings/elements.h"
#include "c-bindings/privatekey.h"
#include "c-bindings/schemes.h"
#include "c-bindings/threshold.h"
#include "c-bindings/bip32/chaincode.h"
#include "c-bindings/bip32/extendedprivatekey.h"
#include "c-bindings/bip32/extendedpublickey.h"

View File

@ -0,0 +1,6 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
// include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
include!("../bindings.rs");

View File

@ -0,0 +1,79 @@
use bls_dash_sys as sys;
#[test]
fn sign_and_verify() {
let seed = b"seedweedseedweedseedweedseedweed";
let bad_seed = b"weedseedweedseedweedseedweedseed";
unsafe {
let scheme = sys::NewAugSchemeMPL();
let mut did_err = false;
let sk = sys::CoreMPLKeyGen(
scheme,
seed.as_ptr() as *const _,
seed.len(),
&mut did_err as *mut _,
);
assert!(!did_err);
let pk = sys::PrivateKeyGetG1Element(sk, &mut did_err as *mut _);
assert!(!did_err);
let sk2 = sys::CoreMPLKeyGen(
scheme,
bad_seed.as_ptr() as *const _,
bad_seed.len(),
&mut did_err as *mut _,
);
assert!(!did_err);
let pk2 = sys::PrivateKeyGetG1Element(sk2, &mut did_err as *mut _);
assert!(!did_err);
let message = b"Evgeny owns 1337 dash no cap";
let sig = sys::CoreMPLSign(scheme, sk, message.as_ptr() as *const _, message.len());
let verify =
sys::CoreMPLVerify(scheme, pk, message.as_ptr() as *const _, message.len(), sig);
assert!(verify);
let verify_bad = sys::CoreMPLVerify(
scheme,
pk2,
message.as_ptr() as *const _,
message.len(),
sig,
);
assert!(!verify_bad);
sys::G2ElementFree(sig);
sys::G1ElementFree(pk2);
sys::PrivateKeyFree(sk2);
sys::G1ElementFree(pk);
sys::PrivateKeyFree(sk);
sys::AugSchemeMPLFree(scheme);
}
}
#[test]
fn test_private_key_from_bip32() {
use std::slice;
let long_seed: [u8; 32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2];
let long_private_key_test_data: [u8; 32] = [50, 67, 148, 112, 207, 6, 210, 118, 137, 125, 27, 144, 105, 189, 214, 228, 68, 83, 144, 205, 80, 105, 133, 222, 14, 26, 28, 136, 167, 111, 241, 118];
let short_seed: [u8; 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let short_private_key_test_data: [u8; 32] = [70, 137, 28, 44, 236, 73, 89, 60, 129, 146, 30, 71, 61, 183, 72, 0, 41, 224, 252, 30, 185, 51, 198, 185, 61, 129, 245, 55, 14, 177, 159, 189];
unsafe {
let c_private_key = sys::PrivateKeyFromSeedBIP32(long_seed.as_ptr() as *const _, long_seed.len());
let serialized = sys::PrivateKeySerialize(c_private_key) as *const u8;
let data = slice::from_raw_parts(serialized, sys::PrivateKeySizeBytes());
assert_eq!(data, &long_private_key_test_data);
sys::PrivateKeyFree(c_private_key);
let c_private_key = sys::PrivateKeyFromSeedBIP32(short_seed.as_ptr() as *const _, short_seed.len());
let serialized = sys::PrivateKeySerialize(c_private_key) as *const u8;
let data = slice::from_raw_parts(serialized, sys::PrivateKeySizeBytes());
assert_eq!(data, &short_private_key_test_data);
sys::PrivateKeyFree(c_private_key);
}
}

View File

@ -0,0 +1,17 @@
unstable_features = true
blank_lines_lower_bound = 0
condense_wildcard_suffixes = true
error_on_line_overflow = true
error_on_unformatted = true
format_code_in_doc_comments = true
format_macro_matchers = true
format_strings = true
imports_granularity = "Crate"
normalize_comments = true
normalize_doc_attributes = true
reorder_impl_items = true
group_imports = "StdExternalCrate"
use_field_init_shorthand = true
use_try_shorthand = true
wrap_comments = true

View File

@ -0,0 +1,18 @@
[package]
name = "bls-signatures"
description = ""
version = "1.2.5"
edition = "2021"
[features]
legacy = []
bip32 = []
use_serde = ["serde"]
dash_helpers = ["rand"]
default = [ "legacy", "bip32", "dash_helpers", "use_serde"]
apple = ["bls-dash-sys/apple"]
[dependencies]
bls-dash-sys = { path = "../bls-dash-sys" }
serde = { version= "1.0.160", features = ["derive"], optional = true}
rand = { version= "0.8.5", optional = true}

View File

@ -0,0 +1,33 @@
use std::ffi::c_void;
use bls_dash_sys::{BIP32ChainCodeFree, BIP32ChainCodeIsEqual, BIP32ChainCodeSerialize};
pub const BIP32_CHAIN_CODE_SIZE: usize = 32;
#[derive(Debug)]
pub struct ChainCode {
pub(crate) c_chain_code: *mut c_void,
}
impl ChainCode {
pub fn serialize(&self) -> Box<[u8; BIP32_CHAIN_CODE_SIZE]> {
unsafe {
let malloc_ptr = BIP32ChainCodeSerialize(self.c_chain_code);
Box::from_raw(malloc_ptr as *mut _)
}
}
}
impl PartialEq for ChainCode {
fn eq(&self, other: &Self) -> bool {
unsafe { BIP32ChainCodeIsEqual(self.c_chain_code, other.c_chain_code) }
}
}
impl Eq for ChainCode {}
impl Drop for ChainCode {
fn drop(&mut self) {
unsafe { BIP32ChainCodeFree(self.c_chain_code) }
}
}

View File

@ -0,0 +1,7 @@
mod chain_code;
mod private_key;
mod public_key;
pub use chain_code::*;
pub use private_key::*;
pub use public_key::*;

View File

@ -0,0 +1,205 @@
use std::ffi::c_void;
use bls_dash_sys::{
BIP32ExtendedPrivateKeyFree, BIP32ExtendedPrivateKeyFromBytes, BIP32ExtendedPrivateKeyFromSeed,
BIP32ExtendedPrivateKeyGetChainCode, BIP32ExtendedPrivateKeyGetExtendedPublicKey,
BIP32ExtendedPrivateKeyGetPrivateKey, BIP32ExtendedPrivateKeyGetPublicKey,
BIP32ExtendedPrivateKeyIsEqual, BIP32ExtendedPrivateKeyPrivateChild,
BIP32ExtendedPrivateKeyPublicChild, BIP32ExtendedPrivateKeySerialize,
};
use crate::{
bip32::{chain_code::ChainCode, ExtendedPublicKey},
utils::{c_err_to_result, SecureBox},
BlsError, G1Element, PrivateKey,
};
pub const BIP32_EXTENDED_PRIVATE_KEY_SIZE: usize = 77;
#[derive(Debug)]
pub struct ExtendedPrivateKey {
c_extended_private_key: *mut c_void,
}
impl PartialEq for ExtendedPrivateKey {
fn eq(&self, other: &Self) -> bool {
unsafe {
BIP32ExtendedPrivateKeyIsEqual(
self.c_extended_private_key,
other.c_extended_private_key,
)
}
}
}
impl Eq for ExtendedPrivateKey {}
impl ExtendedPrivateKey {
pub fn from_bytes(bytes: &[u8]) -> Result<Self, BlsError> {
if bytes.len() != BIP32_EXTENDED_PRIVATE_KEY_SIZE {
return Err(BlsError {
msg: format!(
"Extended Private Key size must be {}, got {}",
BIP32_EXTENDED_PRIVATE_KEY_SIZE,
bytes.len()
),
});
}
Ok(ExtendedPrivateKey {
c_extended_private_key: c_err_to_result(|did_err| unsafe {
BIP32ExtendedPrivateKeyFromBytes(bytes.as_ptr() as *const _, did_err)
})?,
})
}
pub fn from_seed(bytes: &[u8]) -> Result<Self, BlsError> {
Ok(ExtendedPrivateKey {
c_extended_private_key: c_err_to_result(|did_err| unsafe {
BIP32ExtendedPrivateKeyFromSeed(bytes.as_ptr() as *const _, bytes.len(), did_err)
})?,
})
}
pub(crate) fn private_child_with_legacy_flag(&self, index: u32, legacy: bool) -> Self {
ExtendedPrivateKey {
c_extended_private_key: unsafe {
BIP32ExtendedPrivateKeyPrivateChild(self.c_extended_private_key, index, legacy)
},
}
}
pub fn private_child(&self, index: u32) -> Self {
self.private_child_with_legacy_flag(index, false)
}
pub fn public_child(&self, index: u32) -> ExtendedPublicKey {
ExtendedPublicKey {
c_extended_public_key: unsafe {
BIP32ExtendedPrivateKeyPublicChild(self.c_extended_private_key, index)
},
}
}
pub(crate) fn extended_public_key_with_legacy_flag(
&self,
legacy: bool,
) -> Result<ExtendedPublicKey, BlsError> {
Ok(ExtendedPublicKey {
c_extended_public_key: c_err_to_result(|did_err| unsafe {
BIP32ExtendedPrivateKeyGetExtendedPublicKey(
self.c_extended_private_key,
legacy,
did_err,
)
})?,
})
}
pub fn extended_public_key(&self) -> Result<ExtendedPublicKey, BlsError> {
self.extended_public_key_with_legacy_flag(false)
}
pub fn public_key(&self) -> Result<G1Element, BlsError> {
Ok(G1Element {
c_element: c_err_to_result(|did_err| unsafe {
BIP32ExtendedPrivateKeyGetPublicKey(self.c_extended_private_key, did_err)
})?,
})
}
pub fn private_key(&self) -> PrivateKey {
PrivateKey {
c_private_key: unsafe {
BIP32ExtendedPrivateKeyGetPrivateKey(self.c_extended_private_key)
},
}
}
pub fn serialize(&self) -> SecureBox {
unsafe {
let secalloc_ptr = BIP32ExtendedPrivateKeySerialize(self.c_extended_private_key);
SecureBox::from_ptr(secalloc_ptr as *mut u8, BIP32_EXTENDED_PRIVATE_KEY_SIZE)
}
}
pub fn chain_code(&self) -> ChainCode {
ChainCode {
c_chain_code: unsafe {
BIP32ExtendedPrivateKeyGetChainCode(self.c_extended_private_key)
},
}
}
}
impl Drop for ExtendedPrivateKey {
fn drop(&mut self) {
unsafe { BIP32ExtendedPrivateKeyFree(self.c_extended_private_key) }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialize_deserialize() {
let seed = b"seedweedseedweedseedweedseedweed";
let private_key =
ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key");
let private_key_bytes = private_key.serialize();
let private_key_2 = ExtendedPrivateKey::from_bytes(private_key_bytes.as_ref())
.expect("cannot deserialize extended private key");
assert_eq!(private_key, private_key_2);
assert_eq!(private_key.private_key(), private_key_2.private_key());
assert_eq!(private_key.public_key(), private_key_2.public_key());
}
#[test]
fn hierarchical_deterministic_keys() {
let seed = b"seedweedseedweedseedweedseedweed";
let private_key =
ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key()
.expect("cannot get extended public key");
let private_child = private_key.private_child(1337);
let private_grandchild = private_child.private_child(420);
let public_child = public_key.public_child(1337);
let public_grandchild = public_child.public_child(420);
assert_eq!(
public_grandchild,
private_grandchild
.extended_public_key()
.expect("cannot get extended public key")
);
}
#[test]
fn public_keys_match() {
let seed = b"seedweedseedweedseedweedseedweed";
let private_key =
ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key()
.expect("cannot get extended public key");
assert_eq!(private_key.public_key(), Ok(public_key.public_key()));
}
#[test]
fn fingerprint_for_short_bip32_seed() {
assert_eq!(
ExtendedPrivateKey::from_seed(&[1u8, 50, 6, 244, 24, 199, 1, 25])
.expect("cannot generate extended private key")
.public_key()
.expect("cannot get public key from extended private key")
.fingerprint_legacy(),
0xa4700b27
);
}
}

View File

@ -0,0 +1,119 @@
use std::ffi::c_void;
use bls_dash_sys::{
BIP32ExtendedPublicKeyFree, BIP32ExtendedPublicKeyFromBytes,
BIP32ExtendedPublicKeyGetChainCode, BIP32ExtendedPublicKeyGetPublicKey,
BIP32ExtendedPublicKeyIsEqual, BIP32ExtendedPublicKeyPublicChild,
BIP32ExtendedPublicKeySerialize,
};
use crate::{bip32::chain_code::ChainCode, utils::c_err_to_result, BlsError, G1Element};
pub const BIP32_EXTENDED_PUBLIC_KEY_SIZE: usize = 93;
#[derive(Debug)]
pub struct ExtendedPublicKey {
pub(crate) c_extended_public_key: *mut c_void,
}
impl PartialEq for ExtendedPublicKey {
fn eq(&self, other: &Self) -> bool {
unsafe {
BIP32ExtendedPublicKeyIsEqual(self.c_extended_public_key, other.c_extended_public_key)
}
}
}
impl Eq for ExtendedPublicKey {}
impl ExtendedPublicKey {
pub(crate) fn from_bytes_with_legacy_flag(
bytes: &[u8],
legacy: bool,
) -> Result<Self, BlsError> {
if bytes.len() != BIP32_EXTENDED_PUBLIC_KEY_SIZE {
return Err(BlsError {
msg: format!(
"Extended Public Key size must be {}, got {}",
BIP32_EXTENDED_PUBLIC_KEY_SIZE,
bytes.len()
),
});
}
Ok(ExtendedPublicKey {
c_extended_public_key: c_err_to_result(|did_err| unsafe {
BIP32ExtendedPublicKeyFromBytes(bytes.as_ptr() as *const _, legacy, did_err)
})?,
})
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, BlsError> {
Self::from_bytes_with_legacy_flag(bytes, false)
}
pub(crate) fn public_child_with_legacy_flag(&self, index: u32, legacy: bool) -> Self {
ExtendedPublicKey {
c_extended_public_key: unsafe {
BIP32ExtendedPublicKeyPublicChild(self.c_extended_public_key, index, legacy)
},
}
}
pub fn public_child(&self, index: u32) -> Self {
self.public_child_with_legacy_flag(index, false)
}
pub(crate) fn serialize_with_legacy_flag(
&self,
legacy: bool,
) -> Box<[u8; BIP32_EXTENDED_PUBLIC_KEY_SIZE]> {
unsafe {
let malloc_ptr = BIP32ExtendedPublicKeySerialize(self.c_extended_public_key, legacy);
Box::from_raw(malloc_ptr as *mut _)
}
}
pub fn serialize(&self) -> Box<[u8; BIP32_EXTENDED_PUBLIC_KEY_SIZE]> {
self.serialize_with_legacy_flag(false)
}
pub fn chain_code(&self) -> ChainCode {
ChainCode {
c_chain_code: unsafe { BIP32ExtendedPublicKeyGetChainCode(self.c_extended_public_key) },
}
}
pub fn public_key(&self) -> G1Element {
G1Element {
c_element: unsafe { BIP32ExtendedPublicKeyGetPublicKey(self.c_extended_public_key) },
}
}
}
impl Drop for ExtendedPublicKey {
fn drop(&mut self) {
unsafe { BIP32ExtendedPublicKeyFree(self.c_extended_public_key) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bip32::ExtendedPrivateKey;
#[test]
fn serialize_deserialize() {
let seed = b"seedweedseedweedseedweedseedweed";
let private_key =
ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key()
.expect("cannot get extended public key");
let public_key_bytes = public_key.serialize();
let public_key_2 = ExtendedPublicKey::from_bytes(public_key_bytes.as_ref())
.expect("cannot deserialize extended public key");
assert_eq!(public_key, public_key_2);
}
}

View File

@ -0,0 +1,368 @@
use std::ffi::c_void;
use bls_dash_sys::{CoreMPLDeriveChildPkUnhardened, G1ElementFree, G1ElementFromBytes, G1ElementGenerator, G1ElementGetFingerprint, G1ElementIsEqual, G1ElementSerialize, G1ElementCopy, G2ElementCopy, G2ElementFree, G2ElementFromBytes, G2ElementIsEqual, G2ElementSerialize, ThresholdPublicKeyRecover, ThresholdSignatureRecover};
#[cfg(feature = "use_serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{schemes::Scheme, utils::c_err_to_result, BlsError, BasicSchemeMPL};
// TODO Split into modules
pub const G1_ELEMENT_SIZE: usize = 48; // TODO somehow extract it from bls library
pub const G2_ELEMENT_SIZE: usize = 96; // TODO somehow extract it from bls library
#[cfg(feature = "dash_helpers")]
pub type PublicKey = G1Element;
#[cfg(feature = "dash_helpers")]
pub type Signature = G2Element;
#[derive(Debug)]
pub struct G1Element {
pub(crate) c_element: *mut c_void,
}
impl PartialEq for G1Element {
fn eq(&self, other: &Self) -> bool {
unsafe { G1ElementIsEqual(self.c_element, other.c_element) }
}
}
impl Eq for G1Element {}
impl G1Element {
pub fn generate() -> Self {
let c_element = unsafe { G1ElementGenerator() };
G1Element { c_element }
}
#[cfg(feature = "dash_helpers")]
pub fn verify(&self, signature: &G2Element, message: &[u8]) -> bool {
self.verify_basic(signature, message)
}
pub fn verify_basic(&self, signature: &G2Element, message: &[u8]) -> bool {
let basic_scheme = BasicSchemeMPL::new();
basic_scheme.verify(self, message, signature)
}
pub(crate) fn from_bytes_with_legacy_flag(
bytes: &[u8],
legacy: bool,
) -> Result<Self, BlsError> {
if bytes.len() != G1_ELEMENT_SIZE {
return Err(BlsError {
msg: format!(
"G1 Element size must be {}, got {}",
G1_ELEMENT_SIZE,
bytes.len()
),
});
}
Ok(G1Element {
c_element: c_err_to_result(|did_err| unsafe {
G1ElementFromBytes(bytes.as_ptr() as *const _, legacy, did_err)
})?,
})
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, BlsError> {
Self::from_bytes_with_legacy_flag(bytes, false)
}
pub(crate) fn to_bytes_with_legacy_flag(&self, legacy: bool) -> Box<[u8; G1_ELEMENT_SIZE]> {
unsafe {
let malloc_ptr = G1ElementSerialize(self.c_element, legacy);
Box::from_raw(malloc_ptr as *mut _)
}
}
pub fn to_bytes(&self) -> Box<[u8; G1_ELEMENT_SIZE]> {
self.to_bytes_with_legacy_flag(false)
}
pub fn derive_child_public_key_unhardened(
&self,
scheme: &impl Scheme,
index: u32,
) -> G1Element {
G1Element {
c_element: unsafe {
CoreMPLDeriveChildPkUnhardened(scheme.as_mut_ptr(), self.c_element, index)
},
}
}
pub(crate) fn fingerprint_with_legacy_flag(&self, legacy: bool) -> u32 {
unsafe { G1ElementGetFingerprint(self.c_element, legacy) }
}
pub fn fingerprint(&self) -> u32 {
self.fingerprint_with_legacy_flag(false)
}
pub fn threshold_recover(
bls_ids_with_elements: &[(Vec<u8>, G1Element)],
) -> Result<Self, BlsError> {
unsafe {
let len = bls_ids_with_elements.len();
let (c_hashes, c_elements): (Vec<_>, Vec<_>) = bls_ids_with_elements
.iter()
.map(|(hash, element)| {
(
hash.as_ptr() as *mut c_void,
element.c_element as *mut c_void,
)
})
.unzip();
let c_hashes_ptr = c_hashes.as_ptr() as *mut *mut c_void;
let c_elements_ptr = c_elements.as_ptr() as *mut *mut c_void;
Ok(G1Element {
c_element: c_err_to_result(|did_err| {
ThresholdPublicKeyRecover(c_elements_ptr, len, c_hashes_ptr, len, did_err)
})?,
})
}
}
}
impl Clone for G1Element {
fn clone(&self) -> Self {
unsafe {
G1Element{c_element: G1ElementCopy(self.c_element)}
}
}
}
#[cfg(feature = "use_serde")]
// Implement Serialize trait for G1Element
impl Serialize for G1Element {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let bytes = *self.to_bytes();
serializer.serialize_bytes(&bytes)
}
}
#[cfg(feature = "use_serde")]
// Implement Deserialize trait for G1Element
impl<'de> Deserialize<'de> for G1Element {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct G1ElementVisitor;
impl<'de> serde::de::Visitor<'de> for G1ElementVisitor {
type Value = G1Element;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a byte array representing a G1Element")
}
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
G1Element::from_bytes(bytes).map_err(serde::de::Error::custom)
}
}
deserializer.deserialize_bytes(G1ElementVisitor)
}
}
impl Drop for G1Element {
fn drop(&mut self) {
unsafe { G1ElementFree(self.c_element) }
}
}
#[derive(Debug)]
pub struct G2Element {
pub(crate) c_element: *mut c_void,
}
impl PartialEq for G2Element {
fn eq(&self, other: &Self) -> bool {
unsafe { G2ElementIsEqual(self.c_element, other.c_element) }
}
}
impl Eq for G2Element {}
impl G2Element {
pub(crate) fn from_bytes_with_legacy_flag(
bytes: &[u8],
legacy: bool,
) -> Result<Self, BlsError> {
if bytes.len() != G2_ELEMENT_SIZE {
return Err(BlsError {
msg: format!(
"G2 Element size must be {}, got {}",
G2_ELEMENT_SIZE,
bytes.len()
),
});
}
Ok(G2Element {
c_element: c_err_to_result(|did_err| unsafe {
G2ElementFromBytes(bytes.as_ptr() as *const _, legacy, did_err)
})?,
})
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, BlsError> {
Self::from_bytes_with_legacy_flag(bytes, false)
}
pub(crate) fn to_bytes_with_legacy_flag(&self, legacy: bool) -> Box<[u8; G2_ELEMENT_SIZE]> {
unsafe {
let malloc_ptr = G2ElementSerialize(self.c_element, legacy);
Box::from_raw(malloc_ptr as *mut _)
}
}
pub fn to_bytes(&self) -> Box<[u8; G2_ELEMENT_SIZE]> {
self.to_bytes_with_legacy_flag(false)
}
pub fn threshold_recover(
bls_ids_with_elements: &[(Vec<u8>, G2Element)],
) -> Result<Self, BlsError> {
unsafe {
let len = bls_ids_with_elements.len();
let (c_hashes, c_elements): (Vec<_>, Vec<_>) = bls_ids_with_elements
.iter()
.map(|(hash, element)| {
(
hash.as_ptr() as *mut c_void,
element.c_element as *mut c_void,
)
})
.unzip();
let c_hashes_ptr = c_hashes.as_ptr() as *mut *mut c_void;
let c_elements_ptr = c_elements.as_ptr() as *mut *mut c_void;
Ok(G2Element {
c_element: c_err_to_result(|did_err| {
ThresholdSignatureRecover(c_elements_ptr, len, c_hashes_ptr, len, did_err)
})?,
})
}
}
}
impl Clone for G2Element {
fn clone(&self) -> Self {
unsafe {
G2Element{c_element: G2ElementCopy(self.c_element)}
}
}
}
#[cfg(feature = "use_serde")]
// Implement Serialize trait for G1Element
impl Serialize for G2Element {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let bytes = *self.to_bytes();
serializer.serialize_bytes(&bytes)
}
}
#[cfg(feature = "use_serde")]
// Implement Deserialize trait for G1Element
impl<'de> Deserialize<'de> for G2Element {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct G2ElementVisitor;
impl<'de> serde::de::Visitor<'de> for G2ElementVisitor {
type Value = G2Element;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a byte array representing a G2Element")
}
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
G2Element::from_bytes(bytes).map_err(serde::de::Error::custom)
}
}
deserializer.deserialize_bytes(G2ElementVisitor)
}
}
impl Drop for G2Element {
fn drop(&mut self) {
unsafe { G2ElementFree(self.c_element) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
schemes::{AugSchemeMPL, Scheme},
PrivateKey,
};
#[test]
fn g1_serialize_deserialize() {
let seed = b"seedweedseedweedseedweedseedweed";
let scheme = AugSchemeMPL::new();
let sk = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key");
let g1 = sk.g1_element().expect("cannot get G1 element");
let g1_bytes = g1.to_bytes();
let g1_2 =
G1Element::from_bytes(g1_bytes.as_ref()).expect("cannot build G1 element from bytes");
assert_eq!(g1, g1_2);
}
#[test]
fn g2_serialize_deserialize() {
let seed = b"seedweedseedweedseedweedseedweed";
let scheme = AugSchemeMPL::new();
let sk = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key");
let g2 = scheme.sign(&sk, b"ayy");
let g2_bytes = g2.to_bytes();
let g2_2 =
G2Element::from_bytes(g2_bytes.as_ref()).expect("cannot build G2 element from bytes");
assert_eq!(g2, g2_2);
}
#[test]
fn should_generate_new_g1_element() {
let g1_element = G1Element::generate();
assert_eq!(g1_element.to_bytes().len(), 48);
}
#[test]
fn should_return_fingerprint() {
let bytes = [
151, 241, 211, 167, 49, 151, 215, 148, 38, 149, 99, 140, 79, 169, 172, 15, 195, 104,
140, 79, 151, 116, 185, 5, 161, 78, 58, 63, 23, 27, 172, 88, 108, 85, 232, 63, 249,
122, 26, 239, 251, 58, 240, 10, 219, 34, 198, 187,
];
let g1_element =
G1Element::from_bytes(&bytes).expect("should create g1 element from bytes");
assert_eq!(g1_element.fingerprint(), 2093959050);
}
}

View File

@ -0,0 +1,2 @@
mod private_key;
mod public_key;

View File

@ -0,0 +1,58 @@
use crate::{
bip32::{ExtendedPrivateKey, ExtendedPublicKey},
BlsError,
};
impl ExtendedPrivateKey {
pub fn private_child_legacy(&self, index: u32) -> Self {
self.private_child_with_legacy_flag(index, true)
}
pub fn extended_public_key_legacy(&self) -> Result<ExtendedPublicKey, BlsError> {
self.extended_public_key_with_legacy_flag(true)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn serialize_deserialize_legacy() {
let seed = b"seedweedseedweedseedweedseedweed";
let private_key =
ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key_legacy()
.expect("cannot get extended public key");
let public_key_bytes = public_key.serialize_legacy();
let public_key_2 = ExtendedPublicKey::from_bytes_legacy(public_key_bytes.as_ref())
.expect("cannot deserialize extended public key");
assert_eq!(public_key, public_key_2);
}
#[test]
fn hierarchical_deterministic_keys_legacy() {
let seed = b"seedweedseedweedseedweedseedweed";
let private_key =
ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key_legacy()
.expect("cannot get extended public key");
let private_child = private_key.private_child_legacy(1337);
let private_grandchild = private_child.private_child_legacy(420);
let public_child = public_key.public_child_legacy(1337);
let public_grandchild = public_child.public_child_legacy(420);
assert_eq!(
public_grandchild,
private_grandchild
.extended_public_key_legacy()
.expect("cannot get extended public key")
);
}
}

View File

@ -0,0 +1,40 @@
use crate::{
bip32::{ExtendedPublicKey, BIP32_EXTENDED_PUBLIC_KEY_SIZE},
BlsError,
};
impl ExtendedPublicKey {
pub fn from_bytes_legacy(bytes: &[u8]) -> Result<Self, BlsError> {
Self::from_bytes_with_legacy_flag(bytes, true)
}
pub fn public_child_legacy(&self, index: u32) -> Self {
self.public_child_with_legacy_flag(index, true)
}
pub fn serialize_legacy(&self) -> Box<[u8; BIP32_EXTENDED_PUBLIC_KEY_SIZE]> {
self.serialize_with_legacy_flag(true)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bip32::ExtendedPrivateKey;
#[test]
fn serialize_deserialize_legacy() {
let seed = b"seedweedseedweedseedweedseedweed";
let private_key =
ExtendedPrivateKey::from_seed(seed).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key_legacy()
.expect("cannot get extended public key");
let public_key_bytes = public_key.serialize_legacy();
let public_key_2 = ExtendedPublicKey::from_bytes_legacy(public_key_bytes.as_ref())
.expect("cannot deserialize extended public key");
assert_eq!(public_key, public_key_2);
}
}

View File

@ -0,0 +1,25 @@
use crate::{BlsError, G1Element, G2Element, G1_ELEMENT_SIZE, G2_ELEMENT_SIZE};
impl G1Element {
pub fn serialize_legacy(&self) -> Box<[u8; G1_ELEMENT_SIZE]> {
self.to_bytes_with_legacy_flag(true)
}
pub fn from_bytes_legacy(bytes: &[u8]) -> Result<Self, BlsError> {
Self::from_bytes_with_legacy_flag(bytes, true)
}
pub fn fingerprint_legacy(&self) -> u32 {
self.fingerprint_with_legacy_flag(true)
}
}
impl G2Element {
pub fn from_bytes_legacy(bytes: &[u8]) -> Result<Self, BlsError> {
Self::from_bytes_with_legacy_flag(bytes, true)
}
pub fn serialize_legacy(&self) -> Box<[u8; G2_ELEMENT_SIZE]> {
self.to_bytes_with_legacy_flag(true)
}
}

View File

@ -0,0 +1,2 @@
mod bip32;
mod elements;

View File

@ -0,0 +1,104 @@
mod elements;
mod private_key;
mod schemes;
mod utils;
#[cfg(feature = "legacy")]
mod legacy;
#[cfg(feature = "bip32")]
pub mod bip32;
use std::{error::Error, fmt::Display};
pub use elements::{G1Element, G2Element, G1_ELEMENT_SIZE, G2_ELEMENT_SIZE};
#[cfg(feature = "dash_helpers")]
pub use elements::{PublicKey, Signature};
pub use private_key::{PrivateKey, PRIVATE_KEY_SIZE};
pub use schemes::{AugSchemeMPL, BasicSchemeMPL, LegacySchemeMPL, Scheme};
#[derive(Debug, PartialEq)]
pub struct BlsError {
// Need to use owned version as each time BLS has an error its binding glue overwrites error
// message variable.
msg: String,
}
impl Display for BlsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.msg)
}
}
impl Error for BlsError {}
#[cfg(test)]
mod tests {
use super::*;
use crate::schemes::{AugSchemeMPL, Scheme};
#[test]
fn basic_sign() {
let seed = b"seedweedseedweedseedweedseedweed";
let bad_seed = b"weedseedweedseedweedseedweedseed";
let scheme = AugSchemeMPL::new();
let private_key_before =
PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key");
// Also test private key serialization
let private_key_bytes = private_key_before.to_bytes();
let private_key = PrivateKey::from_bytes(private_key_bytes.as_slice(), false)
.expect("cannot build private key from bytes");
drop(private_key_bytes);
let public_key = private_key.g1_element().expect("unable to get public key");
let private_key_bad =
PrivateKey::key_gen(&scheme, bad_seed).expect("unable to generate private key");
let public_key_bad = private_key_bad
.g1_element()
.expect("unable to get public key");
let message = b"Evgeny owns 1337 dash no cap";
let signature = scheme.sign(&private_key, message);
let verify = scheme.verify(&public_key, message, &signature);
assert!(verify);
let verify_bad = scheme.verify(&public_key_bad, message, &signature);
assert!(!verify_bad);
}
#[test]
fn bad_seed() {
let seed = b"lol";
let scheme = AugSchemeMPL::new();
let private_key = PrivateKey::key_gen(&scheme, seed);
assert!(matches!(
private_key,
Err(BlsError { msg }) if msg == "Seed size must be at least 32 bytes"
));
}
#[test]
fn hd_keys_deterministic() {
let seed = b"seedweedseedweedseedweedseedweed";
let scheme = AugSchemeMPL::new();
let master_sk = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key");
let master_pk = master_sk.g1_element().expect("unable to get public key");
let child_sk_u = master_sk.derive_child_private_key_unhardened(&scheme, 22);
let grandchild_sk_u = child_sk_u.derive_child_private_key_unhardened(&scheme, 0);
let child_pk_u = master_pk.derive_child_public_key_unhardened(&scheme, 22);
let grandchild_pk_u = child_pk_u.derive_child_public_key_unhardened(&scheme, 0);
assert_eq!(
grandchild_pk_u,
grandchild_sk_u.g1_element().expect("cannot get public key")
);
}
}

View File

@ -0,0 +1,315 @@
use std::{ffi::c_void, ops::Mul};
use bls_dash_sys::{
CoreMPLDeriveChildSk, CoreMPLDeriveChildSkUnhardened, CoreMPLKeyGen, G1ElementMul,
PrivateKeyFree, PrivateKeyFromBytes, PrivateKeyFromSeedBIP32, PrivateKeyGetG1Element,
PrivateKeyIsEqual, PrivateKeySerialize, ThresholdPrivateKeyRecover,
};
use rand::{prelude::StdRng, Rng};
#[cfg(feature = "use_serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{schemes::Scheme, utils::{c_err_to_result, SecureBox}, BasicSchemeMPL, BlsError, G1Element, G2Element};
pub const PRIVATE_KEY_SIZE: usize = 32; // TODO somehow extract it from bls library
#[derive(Debug)]
pub struct PrivateKey {
pub(crate) c_private_key: *mut c_void,
}
impl PartialEq for PrivateKey {
fn eq(&self, other: &Self) -> bool {
unsafe { PrivateKeyIsEqual(self.c_private_key, other.c_private_key) }
}
}
impl Eq for PrivateKey {}
impl Mul<G1Element> for PrivateKey {
type Output = Result<G1Element, BlsError>;
fn mul(self, rhs: G1Element) -> Self::Output {
Ok(G1Element {
c_element: c_err_to_result(|_| unsafe {
G1ElementMul(rhs.c_element, self.c_private_key)
})?,
})
}
}
impl Mul<PrivateKey> for G1Element {
type Output = Result<G1Element, BlsError>;
fn mul(self, rhs: PrivateKey) -> Self::Output {
rhs * self
}
}
impl PrivateKey {
pub(crate) fn as_mut_ptr(&self) -> *mut c_void {
self.c_private_key
}
// TODO Rename to from_seed
pub fn key_gen(scheme: &impl Scheme, seed: &[u8]) -> Result<Self, BlsError> {
Ok(PrivateKey {
c_private_key: c_err_to_result(|did_err| unsafe {
CoreMPLKeyGen(
scheme.as_mut_ptr(),
seed.as_ptr() as *const _,
seed.len(),
did_err,
)
})?,
})
}
#[cfg(feature = "dash_helpers")]
pub fn generate_dash(rng: &mut StdRng) -> Result<Self, BlsError> {
let seed = rng.gen::<[u8; 32]>();
let scheme = BasicSchemeMPL::new();
Ok(PrivateKey {
c_private_key: c_err_to_result(|did_err| unsafe {
CoreMPLKeyGen(
scheme.as_mut_ptr(),
seed.as_ptr() as *const _,
seed.len(),
did_err,
)
})?,
})
}
#[cfg(feature = "dash_helpers")]
pub fn sign(&self, message: &[u8]) -> G2Element {
self.sign_basic(message)
}
pub fn sign_basic(&self, message: &[u8]) -> G2Element {
let scheme = BasicSchemeMPL::new();
scheme.sign(self, message)
}
#[cfg(feature = "dash_helpers")]
pub fn generate_dash_many(count: usize, rng: &mut StdRng) -> Result<Vec<Self>, BlsError> {
(0..count)
.into_iter()
.map(|_| Self::generate_dash(rng))
.collect()
}
pub fn g1_element(&self) -> Result<G1Element, BlsError> {
Ok(G1Element {
c_element: c_err_to_result(|did_err| unsafe {
PrivateKeyGetG1Element(self.c_private_key, did_err)
})?,
})
}
pub fn to_bytes(&self) -> SecureBox {
// `PrivateKeySerialize` internally securely allocates memory which we have to
// wrap safely
unsafe {
SecureBox::from_ptr(
PrivateKeySerialize(self.c_private_key) as *mut u8,
PRIVATE_KEY_SIZE,
)
}
}
pub fn from_bytes(bytes: &[u8], mod_order: bool) -> Result<Self, BlsError> {
if bytes.len() != PRIVATE_KEY_SIZE {
return Err(BlsError {
msg: format!(
"Private key size must be {}, got {}",
PRIVATE_KEY_SIZE,
bytes.len()
),
});
}
let c_private_key = c_err_to_result(|did_err| unsafe {
PrivateKeyFromBytes(bytes.as_ptr() as *const c_void, mod_order, did_err)
})?;
Ok(PrivateKey { c_private_key })
}
pub fn from_bip32_seed(bytes: &[u8]) -> Self {
let c_private_key =
unsafe { PrivateKeyFromSeedBIP32(bytes.as_ptr() as *const c_void, bytes.len()) };
PrivateKey { c_private_key }
}
pub fn derive_child_private_key(&self, scheme: &impl Scheme, index: u32) -> PrivateKey {
PrivateKey {
c_private_key: unsafe {
CoreMPLDeriveChildSk(scheme.as_mut_ptr(), self.c_private_key, index)
},
}
}
pub fn derive_child_private_key_unhardened(
&self,
scheme: &impl Scheme,
index: u32,
) -> PrivateKey {
PrivateKey {
c_private_key: unsafe {
CoreMPLDeriveChildSkUnhardened(scheme.as_mut_ptr(), self.c_private_key, index)
},
}
}
pub fn threshold_recover(
bls_ids_with_private_keys: &[(Vec<u8>, PrivateKey)],
) -> Result<Self, BlsError> {
unsafe {
let len = bls_ids_with_private_keys.len();
let (c_hashes, c_elements): (Vec<_>, Vec<_>) = bls_ids_with_private_keys
.iter()
.map(|(hash, element)| (hash.as_ptr() as *mut c_void, element.c_private_key))
.unzip();
let c_hashes_ptr = c_hashes.as_ptr() as *mut *mut c_void;
let c_elements_ptr = c_elements.as_ptr() as *mut *mut c_void;
Ok(PrivateKey {
c_private_key: c_err_to_result(|did_err| {
ThresholdPrivateKeyRecover(c_elements_ptr, len, c_hashes_ptr, len, did_err)
})?,
})
}
}
}
impl Clone for PrivateKey {
fn clone(&self) -> Self {
// Serialize the element
let bytes = self.to_bytes();
// We can panic
PrivateKey::from_bytes(bytes.as_slice(), false).expect("expected bytes to be valid")
}
}
#[cfg(feature = "use_serde")]
// Implement Serialize trait for G1Element
impl Serialize for PrivateKey {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_bytes(self.to_bytes().as_slice())
}
}
#[cfg(feature = "use_serde")]
// Implement Deserialize trait for G1Element
impl<'de> Deserialize<'de> for PrivateKey {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct PrivateKeyElementVisitor;
impl<'de> serde::de::Visitor<'de> for PrivateKeyElementVisitor {
type Value = PrivateKey;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a byte array representing a Private Key")
}
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
PrivateKey::from_bytes(bytes, false).map_err(serde::de::Error::custom)
}
}
deserializer.deserialize_bytes(PrivateKeyElementVisitor)
}
}
impl Drop for PrivateKey {
fn drop(&mut self) {
unsafe { PrivateKeyFree(self.c_private_key) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::schemes::AugSchemeMPL;
#[test]
fn serialize_deserialize() {
let seed = b"seedweedseedweedseedweedseedweed";
let scheme = AugSchemeMPL::new();
let sk1 = PrivateKey::key_gen(&scheme, seed).expect("unable to generate private key");
let sk1_bytes = sk1.to_bytes();
let sk2 = PrivateKey::from_bytes(sk1_bytes.as_slice(), false)
.expect("cannot build private key from bytes");
assert_eq!(sk1, sk2);
}
#[test]
fn should_return_private_key_from_bip32_bytes() {
let long_seed = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 1, 2,
];
let long_private_key_test_data = [
50, 67, 148, 112, 207, 6, 210, 118, 137, 125, 27, 144, 105, 189, 214, 228, 68, 83, 144,
205, 80, 105, 133, 222, 14, 26, 28, 136, 167, 111, 241, 118,
];
let long_private_key = PrivateKey::from_bip32_seed(&long_seed);
assert_eq!(*long_private_key.to_bytes(), long_private_key_test_data);
// Previously didn't work with seed with length != 32
let short_seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let short_private_key_test_data = [
70, 137, 28, 44, 236, 73, 89, 60, 129, 146, 30, 71, 61, 183, 72, 0, 41, 224, 252, 30,
185, 51, 198, 185, 61, 129, 245, 55, 14, 177, 159, 189,
];
let short_private_key = PrivateKey::from_bip32_seed(&short_seed);
assert_eq!(*short_private_key.to_bytes(), short_private_key_test_data);
}
#[test]
fn test_keys_multiplication() {
// 46891c2cec49593c81921e473db7480029e0fc1eb933c6b93d81f5370eb19fbd
let private_key_data = [
70, 137, 28, 44, 236, 73, 89, 60, 129, 146, 30, 71, 61, 183, 72, 0, 41, 224, 252, 30,
185, 51, 198, 185, 61, 129, 245, 55, 14, 177, 159, 189,
];
// 0e2f9055c17eb13221d8b41833468ab49f7d4e874ddf4b217f5126392a608fd48ccab3510548f1da4f397c1ad4f8e01a
let public_key_data = [
14, 47, 144, 85, 193, 126, 177, 50, 33, 216, 180, 24, 51, 70, 138, 180, 159, 125, 78,
135, 77, 223, 75, 33, 127, 81, 38, 57, 42, 96, 143, 212, 140, 202, 179, 81, 5, 72, 241,
218, 79, 57, 124, 26, 212, 248, 224, 26,
];
// 03fd387c4d4c66ec9dcdb31ef0c08ad881090dcda13d4b2c9cbc5ef264ff4dc7
let expected_data = [
3, 253, 56, 124, 77, 76, 102, 236, 157, 205, 179, 30, 240, 192, 138, 216, 129, 9, 13,
205, 161, 61, 75, 44, 156, 188, 94, 242, 100, 255, 77, 199,
];
let private_key = PrivateKey::from_bytes(&private_key_data, false).unwrap();
let public_key = G1Element::from_bytes_legacy(&public_key_data).unwrap();
let result = (private_key * public_key).unwrap();
assert_eq!(
&result.serialize_legacy()[..32],
&expected_data,
"should match"
);
let private_key = PrivateKey::from_bytes(&private_key_data, false).unwrap();
let public_key = G1Element::from_bytes_legacy(&public_key_data).unwrap();
let result = (public_key * private_key).unwrap();
assert_eq!(
&result.serialize_legacy()[..32],
&expected_data,
"should match"
);
}
}

View File

@ -0,0 +1,434 @@
use std::ffi::c_void;
use bls_dash_sys::{
AugSchemeMPLAggregateVerify, AugSchemeMPLFree, AugSchemeMPLSign, AugSchemeMPLVerify,
BasicSchemeMPLAggregateVerify, BasicSchemeMPLFree, CoreMPLAggregatePubKeys,
CoreMPLAggregateSigs, CoreMPLSign, CoreMPLVerify, CoreMPLVerifySecure,
LegacySchemeMPLAggregateVerify, LegacySchemeMPLSign, LegacySchemeMPLVerify,
LegacySchemeMPLVerifySecure, NewAugSchemeMPL, NewBasicSchemeMPL, NewLegacySchemeMPL,
};
// TODO Split into modules
use crate::{private_key::PrivateKey, G1Element, G2Element};
pub trait Scheme {
fn as_mut_ptr(&self) -> *mut c_void;
fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element;
fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool;
fn verify_secure<'a>(
&self,
public_keys: impl IntoIterator<Item = &'a G1Element>,
message: &[u8],
signature: &G2Element,
) -> bool {
let mut g1_pointers = public_keys
.into_iter()
.map(|g1| g1.c_element)
.collect::<Vec<_>>();
unsafe {
CoreMPLVerifySecure(
self.as_mut_ptr(),
g1_pointers.as_mut_ptr(),
g1_pointers.len(),
signature.c_element,
message.as_ptr() as *const _,
message.len(),
)
}
}
fn aggregate_public_keys<'a>(
&self,
public_keys: impl IntoIterator<Item = &'a G1Element>,
) -> G1Element {
let mut g1_pointers = public_keys
.into_iter()
.map(|g1| g1.c_element)
.collect::<Vec<_>>();
G1Element {
c_element: unsafe {
CoreMPLAggregatePubKeys(
self.as_mut_ptr(),
g1_pointers.as_mut_ptr(),
g1_pointers.len(),
)
},
}
}
fn aggregate_sigs<'a>(&self, sigs: impl IntoIterator<Item = &'a G2Element>) -> G2Element {
let mut g2_pointers = sigs.into_iter().map(|g2| g2.c_element).collect::<Vec<_>>();
G2Element {
c_element: unsafe {
CoreMPLAggregateSigs(
self.as_mut_ptr(),
g2_pointers.as_mut_ptr(),
g2_pointers.len(),
)
},
}
}
fn aggregate_verify<'a>(
&self,
public_keys: impl IntoIterator<Item = &'a G1Element>,
messages: impl IntoIterator<Item = &'a [u8]>,
signature: &G2Element,
) -> bool;
}
struct AggregateVerifyArgs {
g1_pointers: Vec<*mut c_void>,
messages_pointers: Vec<*const u8>,
messages_lengths: Vec<usize>,
}
// TODO put constructor inside struct?
fn prepare_aggregate_verify_args<'a>(
public_keys: impl IntoIterator<Item = &'a G1Element>,
messages: impl IntoIterator<Item = &'a [u8]>,
) -> AggregateVerifyArgs {
let g1_pointers = public_keys
.into_iter()
.map(|g1| g1.c_element)
.collect::<Vec<_>>();
let mut messages_pointers = Vec::new();
let mut messages_lengths = Vec::new();
for m in messages.into_iter() {
messages_pointers.push(m.as_ptr());
messages_lengths.push(m.len());
}
AggregateVerifyArgs {
g1_pointers,
messages_pointers,
messages_lengths,
}
}
pub struct BasicSchemeMPL {
scheme: *mut c_void,
}
impl BasicSchemeMPL {
pub fn new() -> Self {
BasicSchemeMPL {
scheme: unsafe { NewBasicSchemeMPL() },
}
}
}
impl Scheme for BasicSchemeMPL {
fn as_mut_ptr(&self) -> *mut c_void {
self.scheme
}
fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element {
G2Element {
c_element: unsafe {
CoreMPLSign(
self.scheme,
private_key.as_mut_ptr(),
message.as_ptr() as *const _,
message.len(),
)
},
}
}
fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool {
unsafe {
CoreMPLVerify(
self.scheme,
public_key.c_element,
message.as_ptr() as *const _,
message.len(),
signature.c_element,
)
}
}
fn aggregate_verify<'a>(
&self,
public_keys: impl IntoIterator<Item = &'a G1Element>,
messages: impl IntoIterator<Item = &'a [u8]>,
signature: &G2Element,
) -> bool {
let AggregateVerifyArgs {
mut g1_pointers,
mut messages_pointers,
messages_lengths: mut messages_lengthes,
} = prepare_aggregate_verify_args(public_keys, messages);
unsafe {
BasicSchemeMPLAggregateVerify(
self.as_mut_ptr(),
g1_pointers.as_mut_ptr(),
g1_pointers.len(),
messages_pointers.as_mut_ptr() as *mut _,
messages_lengthes.as_mut_ptr() as *mut _,
messages_pointers.len(),
signature.c_element,
)
}
}
}
pub struct LegacySchemeMPL {
scheme: *mut c_void,
}
impl LegacySchemeMPL {
pub fn new() -> Self {
LegacySchemeMPL {
scheme: unsafe { NewLegacySchemeMPL() },
}
}
}
impl Scheme for LegacySchemeMPL {
fn as_mut_ptr(&self) -> *mut c_void {
self.scheme
}
fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element {
G2Element {
c_element: unsafe {
LegacySchemeMPLSign(
self.scheme,
private_key.as_mut_ptr(),
message.as_ptr() as *const _,
message.len(),
)
},
}
}
fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool {
unsafe {
LegacySchemeMPLVerify(
self.scheme,
public_key.c_element,
message.as_ptr() as *const _,
message.len(),
signature.c_element,
)
}
}
fn verify_secure<'a>(
&self,
public_keys: impl IntoIterator<Item = &'a G1Element>,
message: &[u8],
signature: &G2Element,
) -> bool {
let mut g1_pointers = public_keys
.into_iter()
.map(|g1| g1.c_element)
.collect::<Vec<_>>();
unsafe {
LegacySchemeMPLVerifySecure(
self.as_mut_ptr(),
g1_pointers.as_mut_ptr(),
g1_pointers.len(),
signature.c_element,
message.as_ptr() as *const _,
message.len(),
)
}
}
fn aggregate_verify<'a>(
&self,
public_keys: impl IntoIterator<Item = &'a G1Element>,
messages: impl IntoIterator<Item = &'a [u8]>,
signature: &G2Element,
) -> bool {
let AggregateVerifyArgs {
mut g1_pointers,
mut messages_pointers,
messages_lengths: mut messages_lengthes,
} = prepare_aggregate_verify_args(public_keys, messages);
unsafe {
LegacySchemeMPLAggregateVerify(
self.as_mut_ptr(),
g1_pointers.as_mut_ptr(),
g1_pointers.len(),
messages_pointers.as_mut_ptr() as *mut _,
messages_lengthes.as_mut_ptr() as *mut _,
messages_pointers.len(),
signature.c_element,
)
}
}
}
impl Drop for BasicSchemeMPL {
fn drop(&mut self) {
unsafe { BasicSchemeMPLFree(self.scheme) }
}
}
pub struct AugSchemeMPL {
scheme: *mut c_void,
}
impl AugSchemeMPL {
pub fn new() -> Self {
AugSchemeMPL {
scheme: unsafe { NewAugSchemeMPL() },
}
}
}
impl Scheme for AugSchemeMPL {
fn as_mut_ptr(&self) -> *mut c_void {
self.scheme
}
fn sign(&self, private_key: &PrivateKey, message: &[u8]) -> G2Element {
G2Element {
c_element: unsafe {
AugSchemeMPLSign(
self.scheme,
private_key.as_mut_ptr(),
message.as_ptr() as *const _,
message.len(),
)
},
}
}
fn verify(&self, public_key: &G1Element, message: &[u8], signature: &G2Element) -> bool {
unsafe {
AugSchemeMPLVerify(
self.scheme,
public_key.c_element,
message.as_ptr() as *const _,
message.len(),
signature.c_element,
)
}
}
fn aggregate_verify<'a>(
&self,
public_keys: impl IntoIterator<Item = &'a G1Element>,
messages: impl IntoIterator<Item = &'a [u8]>,
signature: &G2Element,
) -> bool {
let AggregateVerifyArgs {
mut g1_pointers,
mut messages_pointers,
mut messages_lengths,
} = prepare_aggregate_verify_args(public_keys, messages);
unsafe {
AugSchemeMPLAggregateVerify(
self.as_mut_ptr(),
g1_pointers.as_mut_ptr(),
g1_pointers.len(),
messages_pointers.as_mut_ptr() as *mut _,
messages_lengths.as_mut_ptr() as *mut _,
messages_pointers.len(),
signature.c_element,
)
}
}
}
impl Drop for AugSchemeMPL {
fn drop(&mut self) {
unsafe { AugSchemeMPLFree(self.scheme) }
}
}
#[cfg(test)]
mod tests {
use super::*;
fn verify_aggregate(scheme: impl Scheme) {
let seed1 = b"seedweedseedweedseedweedseedweed";
let seed2 = b"weedseedweedseedweedseedweedseed";
let seed3 = b"seedseedseedseedweedweedweedweed";
let seed4 = b"weedweedweedweedweedweedweedweed";
let private_key_1 =
PrivateKey::key_gen(&scheme, seed1).expect("unable to generate private key");
let private_key_2 =
PrivateKey::key_gen(&scheme, seed2).expect("unable to generate private key");
let private_key_3 =
PrivateKey::key_gen(&scheme, seed3).expect("unable to generate private key");
let private_key_4 =
PrivateKey::key_gen(&scheme, seed4).expect("unable to generate private key");
let public_key_1 = private_key_1
.g1_element()
.expect("unable to get public key");
let public_key_2 = private_key_2
.g1_element()
.expect("unable to get public key");
let public_key_3 = private_key_3
.g1_element()
.expect("unable to get public key");
let public_key_4 = private_key_4
.g1_element()
.expect("unable to get public key");
let message_1 = b"ayya";
let message_2 = b"ayyb";
let message_3 = b"ayyc";
let message_4 = b"ayyd";
let signature_1 = scheme.sign(&private_key_1, message_1);
let signature_2 = scheme.sign(&private_key_2, message_2);
let signature_3 = scheme.sign(&private_key_3, message_3);
let signature_4 = scheme.sign(&private_key_4, message_4);
let signature_agg = scheme.aggregate_sigs([&signature_1, &signature_2, &signature_3]);
let verify = scheme.aggregate_verify(
[&public_key_1, &public_key_2, &public_key_3],
[message_1.as_ref(), message_2.as_ref(), message_3.as_ref()],
&signature_agg,
);
assert!(verify);
// Arbitrary trees of aggregates
let signature_agg_final = scheme.aggregate_sigs([&signature_agg, &signature_4]);
let verify_final = scheme.aggregate_verify(
[&public_key_1, &public_key_2, &public_key_3, &public_key_4],
[
message_1.as_ref(),
message_2.as_ref(),
message_3.as_ref(),
message_4.as_ref(),
],
&signature_agg_final,
);
assert!(verify_final);
}
#[test]
fn verify_aggregate_aug() {
verify_aggregate(AugSchemeMPL::new());
}
#[test]
fn verify_aggregate_basic() {
verify_aggregate(BasicSchemeMPL::new());
}
#[test]
fn verify_aggregate_legacy() {
verify_aggregate(LegacySchemeMPL::new());
}
}

View File

@ -0,0 +1,71 @@
use core::slice;
use std::{
ffi::{c_void, CStr},
ops::Deref,
};
use bls_dash_sys::{GetLastErrorMsg, SecAllocBytes, SecFree};
use crate::BlsError;
pub(crate) fn c_err_to_result<T, F>(f: F) -> Result<T, BlsError>
where
F: FnOnce(&mut bool) -> T,
{
let mut did_error = false;
let result = f(&mut did_error);
if did_error {
let error_message = unsafe { CStr::from_ptr(GetLastErrorMsg()) };
Err(BlsError {
msg: String::from_utf8_lossy(error_message.to_bytes()).into_owned(),
})
} else {
Ok(result)
}
}
pub struct SecureBox {
c_sec_alloc: *mut u8,
len: usize,
}
impl SecureBox {
#[allow(dead_code)]
pub(crate) fn new(len: usize) -> Self {
SecureBox {
c_sec_alloc: unsafe { SecAllocBytes(len) },
len,
}
}
pub(crate) unsafe fn from_ptr(ptr: *mut u8, len: usize) -> Self {
SecureBox {
c_sec_alloc: ptr,
len,
}
}
// Somewhere it returns *mut c_void
pub(crate) fn as_mut_ptr(&mut self) -> *mut c_void {
self.c_sec_alloc as *mut c_void
}
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.c_sec_alloc, self.len) }
}
}
impl Deref for SecureBox {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl Drop for SecureBox {
fn drop(&mut self) {
unsafe { SecFree(self.as_mut_ptr()) }
}
}

View File

@ -0,0 +1,7 @@
[package]
name = "example"
version = "0.1.0"
edition = "2021"
[dependencies]
bls-signatures = { path = "../bls-signatures" }

View File

@ -0,0 +1,51 @@
use bls_signatures::{bip32::ExtendedPrivateKey, LegacySchemeMPL, Scheme};
const SEED: &'static [u8] = b"seedweedseedweedseedweedseedweed";
fn check_bip32_hd_keys() {
println!("Check BIP32 hierarchical deterministic keys work");
let private_key =
ExtendedPrivateKey::from_seed(SEED).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key()
.expect("cannot get extended public key");
let private_child = private_key.private_child(1337);
let private_grandchild = private_child.private_child(420);
let public_child = public_key.public_child(1337);
let public_grandchild = public_child.public_child(420);
assert_eq!(
public_grandchild,
private_grandchild
.extended_public_key()
.expect("cannot get extended public key")
);
}
fn check_bip32_legacy_scheme() {
println!("Check BIP32 signing works");
let private_key =
ExtendedPrivateKey::from_seed(SEED).expect("cannot generate extended private key");
let public_key = private_key
.extended_public_key()
.expect("cannot get extended public key");
let scheme = LegacySchemeMPL::new();
let message = b"dash is og";
let signature = scheme.sign(&private_key.private_key(), message);
assert!(scheme.verify(&public_key.public_key(), message, &signature));
}
fn main() {
println!("Run some checks to see if everything is linked up to original BLS library:");
check_bip32_hd_keys();
check_bip32_legacy_scheme();
println!("All checks passed!");
}

View File

@ -0,0 +1,41 @@
diff --git a/include/relic_err.h b/include/relic_err.h
index e16f71fe..a4adb107 100644
--- a/include/relic_err.h
+++ b/include/relic_err.h
@@ -33,7 +33,6 @@
#define RLC_ERR_H
#include <stdint.h>
-#include <setjmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -43,6 +42,10 @@
#include "relic_util.h"
#include "relic_label.h"
+#ifdef CHECK
+#include <setjmp.h>
+#endif
+
/*============================================================================*/
/* Constant definitions */
/*============================================================================*/
@@ -94,6 +97,8 @@ enum errors {
*/
typedef int err_t;
+#ifdef CHECK
+
/**
* Type that describes an error status, including the error code and the program
* location where the error occurred.
@@ -107,6 +112,8 @@ typedef struct _sts_t {
int block;
} sts_t;
+#endif
+
/*============================================================================*/
/* Macro definitions */
/*============================================================================*/

View File

@ -11,8 +11,7 @@ add_library(dashbls
${CMAKE_CURRENT_SOURCE_DIR}/extendedpublickey.cpp
${CMAKE_CURRENT_SOURCE_DIR}/legacy.cpp
${CMAKE_CURRENT_SOURCE_DIR}/schemes.cpp
${CMAKE_CURRENT_SOURCE_DIR}/threshold.cpp
)
${CMAKE_CURRENT_SOURCE_DIR}/threshold.cpp)
target_include_directories(dashbls
PUBLIC

View File

@ -98,6 +98,14 @@ G1Element G1Element::FromNative(const g1_t element)
return ele;
}
G1Element G1Element::Copy() {
G1Element ele;
g1_copy(ele.p, this->p);
return ele;
}
G1Element G1Element::FromMessage(const std::vector<uint8_t>& message,
const uint8_t* dst,
int dst_len)
@ -246,6 +254,7 @@ G2Element G2Element::FromBytesUnchecked(Bytes const bytes, const bool fLegacy)
if (fLegacy) {
std::memcpy(buffer + 1, bytes.begin(), G2Element::SIZE);
buffer[0] = 0x00;
} else {
std::memcpy(buffer + 1, bytes.begin() + G2Element::SIZE / 2, G2Element::SIZE / 2);
std::memcpy(buffer + 1 + G2Element::SIZE / 2, bytes.begin(), G2Element::SIZE / 2);
@ -358,6 +367,14 @@ void G2Element::ToNative(g2_t output) const {
g2_copy(output, (g2_st*)q);
}
G2Element G2Element::Copy() {
G2Element ele;
g2_copy(ele.q, this->q);
return ele;
}
G2Element G2Element::Negate() const
{
G2Element ans;

View File

@ -56,7 +56,7 @@ void TestHKDF(string ikm_hex, string salt_hex, string info_hex, string prk_expec
TEST_CASE("class PrivateKey") {
uint8_t buffer[PrivateKey::PRIVATE_KEY_SIZE];
memcmp(buffer, getRandomSeed().data(), PrivateKey::PRIVATE_KEY_SIZE);
memcpy(buffer, getRandomSeed().data(), PrivateKey::PRIVATE_KEY_SIZE);
SECTION("Copy {constructor|assignment operator}") {
PrivateKey pk1 = PrivateKey::RandomPrivateKey();
PrivateKey pk2 = PrivateKey::RandomPrivateKey();

View File

@ -638,7 +638,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
newList.SetHeight(nHeight);
}
newList.SetBlockHash(block.GetHash());
newList.SetBlockHash(pindex->GetBlockHash());
oldList = GetListForBlock(pindex->pprev);
diff = oldList.BuildDiff(newList);
@ -677,10 +677,10 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockInde
return true;
}
bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex* pindex)
bool CDeterministicMNManager::UndoBlock(const CBlockIndex* pindex)
{
int nHeight = pindex->nHeight;
uint256 blockHash = block.GetHash();
uint256 blockHash = pindex->GetBlockHash();
CDeterministicMNList curList;
CDeterministicMNList prevList;

View File

@ -595,7 +595,7 @@ public:
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state,
const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex);
bool UndoBlock(const CBlockIndex* pindex);
void UpdatedBlockTip(const CBlockIndex* pindex);

View File

@ -11,9 +11,9 @@
#include <script/standard.h>
#include <util/underlying.h>
maybe_error CProRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
maybe_error CProRegTx::IsTriviallyValid(bool is_basic_scheme_active) const
{
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
if (nVersion == 0 || nVersion > GetVersion(is_basic_scheme_active)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
}
if (!IsValidMnType(nType)) {
@ -87,9 +87,9 @@ std::string CProRegTx::ToString() const
nVersion, ToUnderlying(nType), collateralOutpoint.ToStringShort(), addr.ToString(), (double)nOperatorReward / 100, EncodeDestination(PKHash(keyIDOwner)), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
}
maybe_error CProUpServTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
maybe_error CProUpServTx::IsTriviallyValid(bool is_basic_scheme_active) const
{
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
if (nVersion == 0 || nVersion > GetVersion(is_basic_scheme_active)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
}
@ -108,9 +108,9 @@ std::string CProUpServTx::ToString() const
nVersion, ToUnderlying(nType), proTxHash.ToString(), addr.ToString(), payee, platformNodeID.ToString(), platformP2PPort, platformHTTPPort);
}
maybe_error CProUpRegTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
maybe_error CProUpRegTx::IsTriviallyValid(bool is_basic_scheme_active) const
{
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
if (nVersion == 0 || nVersion > GetVersion(is_basic_scheme_active)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
}
if (nMode != 0) {
@ -141,9 +141,9 @@ std::string CProUpRegTx::ToString() const
nVersion, proTxHash.ToString(), pubKeyOperator.ToString(), EncodeDestination(PKHash(keyIDVoting)), payee);
}
maybe_error CProUpRevTx::IsTriviallyValid(bool is_bls_legacy_scheme) const
maybe_error CProUpRevTx::IsTriviallyValid(bool is_basic_scheme_active) const
{
if (nVersion == 0 || nVersion > GetVersion(is_bls_legacy_scheme)) {
if (nVersion == 0 || nVersion > GetVersion(is_basic_scheme_active)) {
return {ValidationInvalidReason::CONSENSUS, "bad-protx-version"};
}

View File

@ -189,7 +189,7 @@ bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, llmq:
}
}
if (!deterministicMNManager->UndoBlock(block, pindex)) {
if (!deterministicMNManager->UndoBlock(pindex)) {
return false;
}

View File

@ -2416,7 +2416,7 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc
node.scheduler->scheduleEvery(std::bind(&CCoinJoinServer::DoMaintenance, std::ref(*::coinJoinServer)), std::chrono::seconds{1});
node.scheduler->scheduleEvery(std::bind(&llmq::CDKGSessionManager::CleanupOldContributions, std::ref(*node.llmq_ctx->qdkgsman)), std::chrono::hours{1});
#ifdef ENABLE_WALLET
} else if(CCoinJoinClientOptions::IsEnabled()) {
} else {
node.scheduler->scheduleEvery(std::bind(&DoCoinJoinMaintenance, std::ref(*node.mempool), std::ref(*node.connman)), std::chrono::seconds{1});
#endif // ENABLE_WALLET
}

View File

@ -135,9 +135,9 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
bool fDIP0008Active_context = nHeight >= chainparams.GetConsensus().DIP0008Height;
pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus(), chainparams.BIP9CheckMasternodesUpgraded());
// -regtest only: allow overriding block.nVersion with
// Non-mainnet only: allow overriding block.nVersion with
// -blockversion=N to test forking scenarios
if (chainparams.MineBlocksOnDemand())
if (Params().NetworkIDString() != CBaseChainParams::MAIN)
pblock->nVersion = gArgs.GetArg("-blockversion", pblock->nVersion);
pblock->nTime = GetAdjustedTime();

View File

@ -22,6 +22,7 @@
#include <QDebug>
#include <QIcon>
#include <QList>
#include <QMessageBox>
// Amount column is right-aligned it contains numbers
@ -73,14 +74,18 @@ public:
void refreshWallet(interfaces::Wallet& wallet)
{
qDebug() << "TransactionTablePriv::refreshWallet";
cachedWallet.clear();
{
parent->beginResetModel();
try {
cachedWallet.clear();
for (const auto& wtx : wallet.getWalletTxs()) {
if (TransactionRecord::showTransaction()) {
cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, wtx));
}
}
} catch(const std::exception& e) {
QMessageBox::critical(nullptr, PACKAGE_NAME, QString("Failed to refresh wallet table: ") + QString::fromStdString(e.what()));
}
parent->endResetModel();
}
/* Update our model of the wallet incrementally, to synchronize our model of the wallet
@ -242,6 +247,11 @@ TransactionTableModel::~TransactionTableModel()
delete priv;
}
void TransactionTableModel::refreshWallet()
{
priv->refreshWallet(walletModel->wallet());
}
/** Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table headers to react. */
void TransactionTableModel::updateAmountColumnTitle()
{
@ -802,18 +812,24 @@ static void ShowProgress(TransactionTableModel *ttm, const std::string &title, i
if (nProgress == 100)
{
fQueueNotifications = false;
if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
assert(invoked);
}
for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
{
if (vQueueNotifications.size() - i <= 10) {
bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
if (vQueueNotifications.size() < 10000) {
if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
assert(invoked);
}
for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
{
if (vQueueNotifications.size() - i <= 10) {
bool invoked = QMetaObject::invokeMethod(ttm, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
assert(invoked);
}
vQueueNotifications[i].invoke(ttm);
vQueueNotifications[i].invoke(ttm);
}
} else {
// it's much faster to just refresh the whole thing instead
bool invoked = QMetaObject::invokeMethod(ttm, "refreshWallet", Qt::QueuedConnection);
assert(invoked);
}
std::vector<TransactionNotification >().swap(vQueueNotifications); // clear
}

View File

@ -113,6 +113,8 @@ private:
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
public Q_SLOTS:
/* Refresh the whole wallet, helpful for huge notification queues */
void refreshWallet();
/* New transaction, or transaction changed status */
void updateTransaction(const QString &hash, int status, bool showTransaction);
void updateAddressBook(const QString &address, const QString &label,

View File

@ -196,10 +196,10 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "echojson", 9, "arg9" },
{ "rescanblockchain", 0, "start_height"},
{ "rescanblockchain", 1, "stop_height"},
{ "wipewallettxes", 0, "keep_confirmed"},
{ "createwallet", 1, "disable_private_keys"},
{ "createwallet", 2, "blank"},
{ "createwallet", 4, "avoid_reuse"},
{ "upgradetohd", 3, "rescan"},
{ "createwallet", 5, "load_on_startup"},
{ "loadwallet", 1, "load_on_startup"},
{ "unloadwallet", 1, "load_on_startup"},

View File

@ -1204,6 +1204,7 @@ static void protx_list_help(const JSONRPCRequest& request)
" registered - List all ProTx which are registered at the given chain height.\n"
" This will also include ProTx which failed PoSe verification.\n"
" valid - List only ProTx which are active/valid at the given chain height.\n"
" hpmn - List only ProTx corresponding to HPMNs at the given chain height.\n"
#ifdef ENABLE_WALLET
" wallet - List only ProTx which are found in your wallet at the given chain height.\n"
" This will also include ProTx which failed PoSe verification.\n"
@ -1349,7 +1350,7 @@ static UniValue protx_list(const JSONRPCRequest& request)
}
});
#endif
} else if (type == "valid" || type == "registered") {
} else if (type == "valid" || type == "registered" || type == "hpmn") {
if (request.params.size() > 3) {
protx_list_help(request);
}
@ -1365,7 +1366,9 @@ static UniValue protx_list(const JSONRPCRequest& request)
CDeterministicMNList mnList = deterministicMNManager->GetListForBlock(::ChainActive()[height]);
bool onlyValid = type == "valid";
bool onlyHPMN = type == "hpmn";
mnList.ForEachMN(onlyValid, [&](const auto& dmn) {
if (onlyHPMN && dmn.nType != MnType::HighPerformance) return;
ret.push_back(BuildDMNListEntry(wallet.get(), dmn, detailed));
});
} else {

View File

@ -37,6 +37,7 @@ static void masternode_list_help(const JSONRPCRequest& request)
"Available modes:\n"
" addr - Print ip address associated with a masternode (can be additionally filtered, partial match)\n"
" recent - Print info in JSON format for active and recently banned masternodes (can be additionally filtered, partial match)\n"
" hpmn - Print info in JSON format for HPMNs only\n"
" full - Print info in format 'status payee lastpaidtime lastpaidblock IP'\n"
" (can be additionally filtered, partial match)\n"
" info - Print info in format 'status payee IP'\n"
@ -581,7 +582,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
strMode != "owneraddress" && strMode != "votingaddress" &&
strMode != "lastpaidtime" && strMode != "lastpaidblock" &&
strMode != "payee" && strMode != "pubkeyoperator" &&
strMode != "status" && strMode != "recent"))
strMode != "status" && strMode != "recent" && strMode != "hpmn"))
{
masternode_list_help(request);
}
@ -609,6 +610,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
};
bool showRecentMnsOnly = strMode == "recent";
bool showHPMNsOnly = strMode == "hpmn";
int tipHeight = WITH_LOCK(cs_main, return ::ChainActive().Tip()->nHeight);
mnList.ForEachMN(false, [&](auto& dmn) {
if (showRecentMnsOnly && mnList.IsMNPoSeBanned(dmn)) {
@ -616,6 +618,9 @@ static UniValue masternodelist(const JSONRPCRequest& request)
return;
}
}
if (showHPMNsOnly && dmn.nType != MnType::HighPerformance) {
return;
}
std::string strOutpoint = dmn.collateralOutpoint.ToStringShort();
Coin coin;
@ -663,7 +668,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
if (strFilter !="" && strInfo.find(strFilter) == std::string::npos &&
strOutpoint.find(strFilter) == std::string::npos) return;
obj.pushKV(strOutpoint, strInfo);
} else if (strMode == "json" || strMode == "recent") {
} else if (strMode == "json" || strMode == "recent" || strMode == "hpmn") {
std::ostringstream streamInfo;
streamInfo << dmn.proTxHash.ToString() << " " <<
dmn.pdmnState->addr.ToString() << " " <<

View File

@ -48,28 +48,28 @@ BOOST_AUTO_TEST_CASE(trivialvalidation_valid)
BOOST_CHECK_EQUAL(txType, "proregtx");
CProRegTx ptx;
BOOST_CHECK(GetTxPayload(tx, ptx, false));
BOOST_CHECK(!ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(!ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
break;
}
case TRANSACTION_PROVIDER_UPDATE_SERVICE: {
BOOST_CHECK_EQUAL(txType, "proupservtx");
CProUpServTx ptx;
BOOST_CHECK(GetTxPayload(tx, ptx, false));
BOOST_CHECK(!ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(!ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
break;
}
case TRANSACTION_PROVIDER_UPDATE_REGISTRAR: {
BOOST_CHECK_EQUAL(txType, "proupregtx");
CProUpRegTx ptx;
BOOST_CHECK(GetTxPayload(tx, ptx, false));
BOOST_CHECK(!ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(!ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
break;
}
case TRANSACTION_PROVIDER_UPDATE_REVOKE: {
BOOST_CHECK_EQUAL(txType, "prouprevtx");
CProUpRevTx ptx;
BOOST_CHECK(GetTxPayload(tx, ptx, false));
BOOST_CHECK(!ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(!ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
break;
}
default:
@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(trivialvalidation_invalid)
if (txType == "proregtx") {
CProRegTx ptx;
if (GetTxPayload(tx, ptx, false)) {
BOOST_CHECK(ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
} else {
BOOST_CHECK(tx.nType != TRANSACTION_PROVIDER_REGISTER || ptx.nVersion == 0);
}
@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(trivialvalidation_invalid)
else if (txType == "proupservtx") {
CProUpServTx ptx;
if (GetTxPayload(tx, ptx, false)) {
BOOST_CHECK(ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
} else {
BOOST_CHECK(tx.nType != TRANSACTION_PROVIDER_UPDATE_SERVICE || ptx.nVersion == 0);
}
@ -127,7 +127,7 @@ BOOST_AUTO_TEST_CASE(trivialvalidation_invalid)
else if (txType == "proupregtx") {
CProUpRegTx ptx;
if (GetTxPayload(tx, ptx, false)) {
BOOST_CHECK(ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
}
else {
BOOST_CHECK(tx.nType != TRANSACTION_PROVIDER_UPDATE_REGISTRAR || ptx.nVersion == 0);
@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(trivialvalidation_invalid)
else if (txType == "prouprevtx") {
CProUpRevTx ptx;
if (GetTxPayload(tx, ptx, false)) {
BOOST_CHECK(ptx.IsTriviallyValid(bls::bls_legacy_scheme.load()).did_err);
BOOST_CHECK(ptx.IsTriviallyValid(!bls::bls_legacy_scheme.load()).did_err);
} else {
BOOST_CHECK(tx.nType != TRANSACTION_PROVIDER_UPDATE_REVOKE || ptx.nVersion == 0);
}

View File

@ -365,6 +365,15 @@ CBlock TestChainSetup::CreateBlock(const std::vector<CMutableTransaction>& txns,
TestChainSetup::~TestChainSetup()
{
// Allow tx index to catch up with the block index cause otherwise
// we might be destroying it while scheduler still has some work for it
// e.g. via BlockConnected signal
int64_t time_start = GetTimeMillis();
while (!g_txindex->BlockUntilSyncedToCurrentChain()) {
static constexpr int64_t timeout_ms = 10 * 1000;
assert(time_start + timeout_ms > GetTimeMillis());
UninterruptibleSleep(std::chrono::milliseconds{100});
}
g_txindex->Interrupt();
g_txindex->Stop();
g_txindex.reset();

View File

@ -70,6 +70,18 @@ bool ReadSettings(const fs::path& path, std::map<std::string, SettingsValue>& va
return false;
}
// Check if settings file is empty
if (file.peek() == std::ifstream::traits_type::eof()) {
// In that case delete it and return true: it will be created with default value later
file.close();
if (!boost::filesystem::remove(path)) {
// Return false only if it failed to delete the empty settings file
errors.emplace_back(strprintf("Unable to delete empty settings file %s", path.string()));
return false;
}
return true;
}
SettingsValue in;
if (!in.read(std::string{std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()})) {
errors.emplace_back(strprintf("Unable to parse settings file %s", path.string()));

View File

@ -2665,67 +2665,66 @@ static UniValue upgradetohd(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
}
LOCK(pwallet->cs_wallet);
// Do not do anything to HD wallets
if (pwallet->IsHDEnabled()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot upgrade a wallet to HD if it is already upgraded to HD.");
}
if (!pwallet->SetMaxVersion(FEATURE_HD)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot downgrade wallet");
}
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
bool prev_encrypted = pwallet->IsCrypted();
SecureString secureWalletPassphrase;
secureWalletPassphrase.reserve(100);
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
if (request.params[2].isNull()) {
if (prev_encrypted) {
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Cannot upgrade encrypted wallet to HD without the wallet passphrase");
}
} else {
secureWalletPassphrase = request.params[2].get_str().c_str();
if (!pwallet->Unlock(secureWalletPassphrase)) {
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "The wallet passphrase entered was incorrect");
}
}
bool generate_mnemonic = request.params[0].isNull() || request.params[0].get_str().empty();
SecureString secureMnemonic;
secureMnemonic.reserve(256);
if (!generate_mnemonic) {
if (pwallet->chain().isInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot set mnemonic while still in Initial Block Download");
{
LOCK(pwallet->cs_wallet);
// Do not do anything to HD wallets
if (pwallet->IsHDEnabled()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot upgrade a wallet to HD if it is already upgraded to HD.");
}
secureMnemonic = request.params[0].get_str().c_str();
}
SecureString secureMnemonicPassphrase;
secureMnemonicPassphrase.reserve(256);
if (!request.params[1].isNull()) {
secureMnemonicPassphrase = request.params[1].get_str().c_str();
}
pwallet->WalletLogPrintf("Upgrading wallet to HD\n");
pwallet->SetMinVersion(FEATURE_HD);
if (prev_encrypted) {
if (!spk_man->GenerateNewHDChainEncrypted(secureMnemonic, secureMnemonicPassphrase, secureWalletPassphrase)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to generate encrypted HD wallet");
if (!pwallet->SetMaxVersion(FEATURE_HD)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot downgrade wallet");
}
} else {
spk_man->GenerateNewHDChain(secureMnemonic, secureMnemonicPassphrase);
if (!secureWalletPassphrase.empty()) {
if (!pwallet->EncryptWallet(secureWalletPassphrase)) {
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Failed to encrypt HD wallet");
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
}
bool prev_encrypted = pwallet->IsCrypted();
SecureString secureWalletPassphrase;
secureWalletPassphrase.reserve(100);
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
if (request.params[2].isNull()) {
if (prev_encrypted) {
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Cannot upgrade encrypted wallet to HD without the wallet passphrase");
}
} else {
secureWalletPassphrase = request.params[2].get_str().c_str();
if (!pwallet->Unlock(secureWalletPassphrase)) {
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "The wallet passphrase entered was incorrect");
}
}
SecureString secureMnemonic;
secureMnemonic.reserve(256);
if (!generate_mnemonic) {
secureMnemonic = request.params[0].get_str().c_str();
}
SecureString secureMnemonicPassphrase;
secureMnemonicPassphrase.reserve(256);
if (!request.params[1].isNull()) {
secureMnemonicPassphrase = request.params[1].get_str().c_str();
}
pwallet->WalletLogPrintf("Upgrading wallet to HD\n");
pwallet->SetMinVersion(FEATURE_HD);
if (prev_encrypted) {
if (!spk_man->GenerateNewHDChainEncrypted(secureMnemonic, secureMnemonicPassphrase, secureWalletPassphrase)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Failed to generate encrypted HD wallet");
}
} else {
spk_man->GenerateNewHDChain(secureMnemonic, secureMnemonicPassphrase);
if (!secureWalletPassphrase.empty()) {
if (!pwallet->EncryptWallet(secureWalletPassphrase)) {
throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Failed to encrypt HD wallet");
}
}
}
}
@ -2737,7 +2736,16 @@ static UniValue upgradetohd(const JSONRPCRequest& request)
if (!reserver.reserve()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
}
pwallet->ScanForWalletTransactions(pwallet->chain().getBlockHash(0), {}, reserver, true);
CWallet::ScanResult result = pwallet->ScanForWalletTransactions(pwallet->chain().getBlockHash(0), {}, reserver, true);
switch (result.status) {
case CWallet::ScanResult::SUCCESS:
break;
case CWallet::ScanResult::FAILURE:
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
case CWallet::ScanResult::USER_ABORT:
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
// no default case, so the compiler can warn about missing cases
}
}
return true;
@ -3564,6 +3572,74 @@ static UniValue rescanblockchain(const JSONRPCRequest& request)
return response;
}
static UniValue wipewallettxes(const JSONRPCRequest& request)
{
RPCHelpMan{"wipewallettxes",
"\nWipe wallet transactions.\n"
"Note: Use \"rescanblockchain\" to initiate the scanning progress and recover wallet transactions.\n",
{
{"keep_confirmed", RPCArg::Type::BOOL, /* default */ "false", "Do not wipe confirmed transactions"},
},
RPCResult{RPCResult::Type::NONE, "", ""},
RPCExamples{
HelpExampleCli("wipewallettxes", "")
+ HelpExampleRpc("wipewallettxes", "")
},
}.Check(request);
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
WalletRescanReserver reserver(pwallet);
if (!reserver.reserve()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort rescan or wait.");
}
LOCK(pwallet->cs_wallet);
bool keep_confirmed{false};
if (!request.params[0].isNull()) {
keep_confirmed = request.params[0].get_bool();
}
const size_t WALLET_SIZE{pwallet->mapWallet.size()};
const size_t STEPS{20};
const size_t BATCH_SIZE = std::max(WALLET_SIZE / STEPS, size_t(1000));
pwallet->ShowProgress(strprintf("%s " + _("Wiping wallet transactions...").translated, pwallet->GetDisplayName()), 0);
for (size_t progress = 0; progress < STEPS; ++progress) {
std::vector<uint256> vHashIn;
std::vector<uint256> vHashOut;
size_t count{0};
for (auto& [txid, wtx] : pwallet->mapWallet) {
if (progress < STEPS - 1 && ++count > BATCH_SIZE) break;
if (keep_confirmed && wtx.m_confirm.status == CWalletTx::CONFIRMED) continue;
vHashIn.push_back(txid);
}
if (vHashIn.size() > 0 && pwallet->ZapSelectTx(vHashIn, vHashOut) != DBErrors::LOAD_OK) {
pwallet->ShowProgress(strprintf("%s " + _("Wiping wallet transactions...").translated, pwallet->GetDisplayName()), 100);
throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete transactions.");
}
CHECK_NONFATAL(vHashOut.size() == vHashIn.size());
if (pwallet->IsAbortingRescan() || pwallet->chain().shutdownRequested()) {
pwallet->ShowProgress(strprintf("%s " + _("Wiping wallet transactions...").translated, pwallet->GetDisplayName()), 100);
throw JSONRPCError(RPC_MISC_ERROR, "Wiping was aborted by user.");
}
pwallet->ShowProgress(strprintf("%s " + _("Wiping wallet transactions...").translated, pwallet->GetDisplayName()), std::max(1, std::min(99, int(progress * 100 / STEPS))));
}
pwallet->ShowProgress(strprintf("%s " + _("Wiping wallet transactions...").translated, pwallet->GetDisplayName()), 100);
return NullUniValue;
}
class DescribeWalletAddressVisitor
{
public:
@ -4166,6 +4242,7 @@ static const CRPCCommand commands[] =
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout","mixingonly"} },
{ "wallet", "walletprocesspsbt", &walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} },
{ "wallet", "walletcreatefundedpsbt", &walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} },
{ "wallet", "wipewallettxes", &wipewallettxes, {"keep_confirmed"} },
};
// clang-format on

View File

@ -7,6 +7,7 @@
#include <coinjoin/client.h>
#include <logging.h>
#include <script/descriptor.h>
#include <shutdown.h>
#include <util/bip32.h>
#include <util/strencodings.h>
#include <util/system.h>
@ -1374,14 +1375,27 @@ bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize)
{
// don't create extra internal keys
missingInternal = 0;
} else {
nTargetSize *= 2;
}
const int64_t total_missing = missingInternal + missingExternal;
if (total_missing == 0) return true;
constexpr int64_t PROGRESS_REPORT_INTERVAL = 1; // in seconds
const bool should_show_progress = total_missing > 100;
const std::string strMsg = _("Topping up keypool...").translated;
int64_t progress_report_time = GetTime();
WalletLogPrintf("%s\n", strMsg);
if (should_show_progress) {
uiInterface.ShowProgress(strMsg, 0, false);
}
bool fInternal = false;
int64_t current_index{0};
WalletBatch batch(m_storage.GetDatabase());
for (int64_t i = missingInternal + missingExternal; i--;)
{
if (i < missingInternal) {
for (current_index = 0; current_index < total_missing; ++current_index) {
if (current_index == missingExternal) {
fInternal = true;
}
@ -1389,15 +1403,20 @@ bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize)
CPubKey pubkey(GenerateNewKey(batch, 0, fInternal));
AddKeypoolPubkeyWithDB(pubkey, fInternal, batch);
if (missingInternal + missingExternal > 0) {
WalletLogPrintf("keypool added %d keys (%d internal), size=%u (%u internal)\n",
missingInternal + missingExternal, missingInternal,
setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size());
if (GetTime() >= progress_report_time + PROGRESS_REPORT_INTERVAL) {
const double dProgress = 100.f * current_index / total_missing;
progress_report_time = GetTime();
WalletLogPrintf("Still topping up. At key %lld. Progress=%f\n", current_index, dProgress);
if (should_show_progress) {
uiInterface.ShowProgress(strMsg, static_cast<int>(dProgress), false);
}
}
double dProgress = 100.f * m_max_keypool_index / (nTargetSize + 1);
std::string strMsg = strprintf(_("Loading wallet... (%3.2f %%)").translated, dProgress);
uiInterface.InitMessage(strMsg);
if (ShutdownRequested()) break;
}
WalletLogPrintf("Keypool added %d keys, size=%u (%u internal)\n",
current_index + 1, setInternalKeyPool.size() + setExternalKeyPool.size(), setInternalKeyPool.size());
if (should_show_progress) {
uiInterface.ShowProgress("", 100, false);
}
}
NotifyCanGetAddressesChanged();

View File

@ -1884,7 +1884,6 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc
WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString());
fAbortRescan = false;
ShowProgress(strprintf("%s " + _("Rescanning...").translated, GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup
uint256 tip_hash;
// The way the 'block_height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0.
@ -3667,6 +3666,9 @@ void CWallet::AutoLockMasternodeCollaterals()
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{
AssertLockHeld(cs_wallet);
WalletLogPrintf("ZapSelectTx started for %d transactions...\n", vHashIn.size());
DBErrors nZapSelectTxRet = WalletBatch(*database).ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut) {
const auto& it = mapWallet.find(hash);
@ -3690,6 +3692,8 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
MarkDirty();
WalletLogPrintf("ZapSelectTx completed for %d transactions.\n", vHashOut.size());
return DBErrors::LOAD_OK;
}

View File

@ -654,7 +654,7 @@ private:
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly = false, bool accept_no_keys = false);
std::atomic<bool> fAbortRescan{false};
std::atomic<bool> fAbortRescan{false}; // reset by WalletRescanReserver::reserve()
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
std::atomic<int64_t> m_scanning_start{0};
std::atomic<double> m_scanning_progress{0};
@ -1306,6 +1306,7 @@ public:
}
m_wallet->m_scanning_start = GetTimeMillis();
m_wallet->m_scanning_progress = 0;
m_wallet->fAbortRescan = false;
m_could_reserve = true;
return true;
}

View File

@ -112,7 +112,7 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
WalletShowInfo(wallet_instance.get());
wallet_instance->Close();
}
} else if (command == "info" || command == "salvage") {
} else if (command == "info" || command == "salvage" || command == "wipetxes") {
if (command == "info") {
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ false);
if (!wallet_instance) return false;
@ -135,6 +135,32 @@ bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
#else
tfm::format(std::cerr, "Salvage command is not available as BDB support is not compiled");
return false;
#endif
} else if (command == "wipetxes") {
#ifdef USE_BDB
std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ false);
if (wallet_instance == nullptr) return false;
std::vector<uint256> vHash;
std::vector<uint256> vHashOut;
LOCK(wallet_instance->cs_wallet);
for (auto& [txid, _] : wallet_instance->mapWallet) {
vHash.push_back(txid);
}
if (wallet_instance->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) {
tfm::format(std::cerr, "Could not properly delete transactions");
wallet_instance->Close();
return false;
}
wallet_instance->Close();
return vHashOut.size() == vHash.size();
#else
tfm::format(std::cerr, "Wipetxes command is not available as BDB support is not compiled");
return false;
#endif
}
} else {

View File

@ -0,0 +1,41 @@
#!/usr/bin/env python3
# Copyright (c) 2023 The Dash Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test transaction wiping using the wipewallettxes RPC."""
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error
class WipeWalletTxesTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self):
self.log.info("Test that wipewallettxes removes txes and rescanblockchain is able to recover them")
self.nodes[0].generate(101)
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
self.nodes[0].generate(1)
assert_equal(self.nodes[0].getwalletinfo()["txcount"], 103)
self.nodes[0].wipewallettxes()
assert_equal(self.nodes[0].getwalletinfo()["txcount"], 0)
self.nodes[0].rescanblockchain()
assert_equal(self.nodes[0].getwalletinfo()["txcount"], 103)
self.log.info("Test that wipewallettxes removes txes but keeps confirmed ones when asked to")
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
assert_equal(self.nodes[0].getwalletinfo()["txcount"], 104)
self.nodes[0].wipewallettxes(True)
assert_equal(self.nodes[0].getwalletinfo()["txcount"], 103)
self.nodes[0].rescanblockchain()
assert_equal(self.nodes[0].getwalletinfo()["txcount"], 103)
assert_raises_rpc_error(-5, "Invalid or non-wallet transaction id", self.nodes[0].gettransaction, txid)
if __name__ == '__main__':
WipeWalletTxesTest().main()

View File

@ -239,6 +239,7 @@ BASE_SCRIPTS = [
'wallet_create_tx.py',
'p2p_fingerprint.py',
'rpc_platform_filter.py',
'rpc_wipewallettxes.py',
'feature_dip0020_activation.py',
'feature_uacomment.py',
'wallet_coinbase_category.py',

View File

@ -228,6 +228,31 @@ class ToolWalletTest(BitcoinTestFramework):
self.assert_tool_output('', '-wallet=salvage', 'salvage')
def test_wipe(self):
out = textwrap.dedent('''\
Wallet info
===========
Encrypted: no
HD (hd seed available): yes
Keypool Size: 2
Transactions: 1
Address Book: 1
''')
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
self.assert_tool_output('', '-wallet=' + self.default_wallet_name, 'wipetxes')
out = textwrap.dedent('''\
Wallet info
===========
Encrypted: no
HD (hd seed available): yes
Keypool Size: 2
Transactions: 0
Address Book: 1
''')
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
def run_test(self):
self.wallet_path = os.path.join(self.nodes[0].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename)
self.test_invalid_tool_commands_and_args()
@ -238,6 +263,7 @@ class ToolWalletTest(BitcoinTestFramework):
self.test_getwalletinfo_on_different_wallet()
if self.is_bdb_compiled():
self.test_salvage()
self.test_wipe()
if __name__ == '__main__':
ToolWalletTest().main()