diff --git a/.github/workflows/move.yml b/.github/workflows/move.yml new file mode 100644 index 00000000000000..62d4f8f67734e1 --- /dev/null +++ b/.github/workflows/move.yml @@ -0,0 +1,15 @@ +name: Move + +on: + push: + branches: [ ] + pull_request: + branches: [ ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 00000000000000..97f73f3d57d558 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,22 @@ +name: Rust + +on: + push: + branches: [ ] + pull_request: + branches: [ ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose diff --git a/aptos-move/aptos-vm/src/natives.rs b/aptos-move/aptos-vm/src/natives.rs index 1ff10bb7da49b8..5073ffa4cebd23 100644 --- a/aptos-move/aptos-vm/src/natives.rs +++ b/aptos-move/aptos-vm/src/natives.rs @@ -202,10 +202,10 @@ pub fn assert_no_test_natives(err_msg: &str) { || module_name.as_str() == "multi_ed25519" && func_name.as_str() == "generate_keys_internal" || module_name.as_str() == "multi_ed25519" && func_name.as_str() == "sign_internal" - || module_name.as_str() == "bls12381" + || module_name.as_str() == "ed25519" && func_name.as_str() == "generate_keys_internal" - || module_name.as_str() == "bls12381" && func_name.as_str() == "sign_internal" - || module_name.as_str() == "bls12381" + || module_name.as_str() == "ed25519" && func_name.as_str() == "sign_internal" + || module_name.as_str() == "ed25519" && func_name.as_str() == "generate_proof_of_possession_internal" || module_name.as_str() == "event" && func_name.as_str() == "emitted_events_internal") diff --git a/aptos-move/e2e-move-tests/src/stake.rs b/aptos-move/e2e-move-tests/src/stake.rs index 566e94023ad49c..2f2af49f05d79c 100644 --- a/aptos-move/e2e-move-tests/src/stake.rs +++ b/aptos-move/e2e-move-tests/src/stake.rs @@ -3,7 +3,7 @@ use crate::harness::MoveHarness; use aptos_cached_packages::aptos_stdlib; -use aptos_crypto::{bls12381, PrivateKey, Uniform}; +use aptos_crypto::{ed25519, PrivateKey, Uniform}; use aptos_language_e2e_tests::account::Account; use aptos_types::{ account_address::AccountAddress, account_config::CORE_CODE_ADDRESS, @@ -76,18 +76,11 @@ pub fn rotate_consensus_key( account: &Account, pool_address: AccountAddress, ) -> TransactionStatus { - let consensus_key = bls12381::PrivateKey::generate_for_testing(); + let consensus_key = ed25519::PrivateKey::generate_for_testing(); let consensus_pubkey = consensus_key.public_key().to_bytes().to_vec(); - let proof_of_possession = bls12381::ProofOfPossession::create(&consensus_key) - .to_bytes() - .to_vec(); harness.run_transaction_payload( account, - aptos_stdlib::stake_rotate_consensus_key( - pool_address, - consensus_pubkey, - proof_of_possession, - ), + aptos_stdlib::stake_rotate_consensus_key(pool_address, consensus_pubkey), ) } diff --git a/aptos-move/e2e-move-tests/src/tests/gas.rs b/aptos-move/e2e-move-tests/src/tests/gas.rs index 3b542a2614c97a..627588d07d8f20 100644 --- a/aptos-move/e2e-move-tests/src/tests/gas.rs +++ b/aptos-move/e2e-move-tests/src/tests/gas.rs @@ -12,7 +12,7 @@ use crate::{ MoveHarness, }; use aptos_cached_packages::{aptos_stdlib, aptos_token_sdk_builder}; -use aptos_crypto::{bls12381, PrivateKey, Uniform}; +use aptos_crypto::{ed25519, PrivateKey, Uniform}; use aptos_gas_profiling::TransactionGasLog; use aptos_types::{ account_address::{default_stake_pool_address, AccountAddress}, @@ -145,20 +145,13 @@ fn test_gas() { ), ); let pool_address = default_stake_pool_address(account_1_address, account_2_address); - let consensus_key = bls12381::PrivateKey::generate_for_testing(); + let consensus_key = ed25519::PrivateKey::generate_for_testing(); let consensus_pubkey = consensus_key.public_key().to_bytes().to_vec(); - let proof_of_possession = bls12381::ProofOfPossession::create(&consensus_key) - .to_bytes() - .to_vec(); run( &mut harness, "RotateConsensusKey", account_2, - aptos_stdlib::stake_rotate_consensus_key( - pool_address, - consensus_pubkey, - proof_of_possession, - ), + aptos_stdlib::stake_rotate_consensus_key(pool_address, consensus_pubkey), ); run( &mut harness, diff --git a/aptos-move/framework/aptos-framework/doc/genesis.md b/aptos-move/framework/aptos-framework/doc/genesis.md index b942bf5f86e5fe..ac9224a7cf553f 100644 --- a/aptos-move/framework/aptos-framework/doc/genesis.md +++ b/aptos-move/framework/aptos-framework/doc/genesis.md @@ -779,7 +779,6 @@ encoded in a single BCS byte array. operator, pool_address, validator.consensus_pubkey, - validator.proof_of_possession, ); stake::update_network_and_fullnode_addresses( operator, diff --git a/aptos-move/framework/aptos-framework/doc/stake.md b/aptos-move/framework/aptos-framework/doc/stake.md index 3474162b538baa..3152a55531eb36 100644 --- a/aptos-move/framework/aptos-framework/doc/stake.md +++ b/aptos-move/framework/aptos-framework/doc/stake.md @@ -149,7 +149,6 @@ or if their stake drops below the min required, they would get removed at the en
use 0x1::account;
use 0x1::aptos_coin;
-use 0x1::bls12381;
use 0x1::coin;
use 0x1::error;
use 0x1::event;
@@ -1959,7 +1958,7 @@ to set later.
Initialize the validator account and give ownership to the signing account.
-public entry fun initialize_validator(account: &signer, consensus_pubkey: vector<u8>, proof_of_possession: vector<u8>, network_addresses: vector<u8>, fullnode_addresses: vector<u8>)
+public entry fun initialize_validator(account: &signer, consensus_pubkey: vector<u8>, network_addresses: vector<u8>, fullnode_addresses: vector<u8>)
@@ -1971,17 +1970,10 @@ Initialize the validator account and give ownership to the signing account.
public entry fun initialize_validator(
account: &signer,
consensus_pubkey: vector<u8>,
- proof_of_possession: vector<u8>,
network_addresses: vector<u8>,
fullnode_addresses: vector<u8>,
) acquires AllowedValidators {
// Checks the public key has a valid proof-of-possession to prevent rogue-key attacks.
- let pubkey_from_pop = &mut bls12381::public_key_from_bytes_with_pop(
- consensus_pubkey,
- &proof_of_possession_from_bytes(proof_of_possession)
- );
- assert!(option::is_some(pubkey_from_pop), error::invalid_argument(EINVALID_PUBLIC_KEY));
-
initialize_owner(account);
move_to(account, ValidatorConfig {
consensus_pubkey,
@@ -2417,7 +2409,7 @@ Move amount
of coins from pending_inactive to active.
-fun rotate_consensus_key_internal(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>, proof_of_possession: vector<u8>, genesis: bool)
+fun rotate_consensus_key_internal(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>, genesis: bool)
@@ -2430,7 +2422,6 @@ Move amount
of coins from pending_inactive to active.
operator: &signer,
pool_address: address,
new_consensus_pubkey: vector<u8>,
- proof_of_possession: vector<u8>,
genesis: bool,
) acquires StakePool, ValidatorConfig {
assert_stake_pool_exists(pool_address);
@@ -2441,16 +2432,6 @@ Move amount
of coins from pending_inactive to active.
let validator_info = borrow_global_mut<ValidatorConfig>(pool_address);
let old_consensus_pubkey = validator_info.consensus_pubkey;
// Checks the public key has a valid proof-of-possession to prevent rogue-key attacks.
- if (!genesis) {
- let pubkey_from_pop = &mut bls12381::public_key_from_bytes_with_pop(
- new_consensus_pubkey,
- &proof_of_possession_from_bytes(proof_of_possession)
- );
- assert!(option::is_some(pubkey_from_pop), error::invalid_argument(EINVALID_PUBLIC_KEY));
- } else {
- let pubkey = &mut bls12381::public_key_from_bytes(new_consensus_pubkey);
- assert!(option::is_some(pubkey), error::invalid_argument(EINVALID_PUBLIC_KEY));
- };
validator_info.consensus_pubkey = new_consensus_pubkey;
event::emit_event(
@@ -2477,7 +2458,7 @@ does not verify proof of possession
only for genesis
-public(friend) fun rotate_consensus_key_genesis(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>, proof_of_poseesion: vector<u8>)
+public(friend) fun rotate_consensus_key_genesis(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>)
@@ -2490,9 +2471,8 @@ only for genesis
operator: &signer,
pool_address: address,
new_consensus_pubkey: vector<u8>,
- proof_of_poseesion: vector<u8>,
) acquires StakePool, ValidatorConfig {
- rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, proof_of_poseesion, true);
+ rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, true);
}
@@ -2507,7 +2487,7 @@ only for genesis
Rotate the consensus key of the validator, it'll take effect in next epoch.
-public entry fun rotate_consensus_key(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>, proof_of_possession: vector<u8>)
+public entry fun rotate_consensus_key(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>)
@@ -2520,9 +2500,8 @@ Rotate the consensus key of the validator, it'll take effect in next epoch.
operator: &signer,
pool_address: address,
new_consensus_pubkey: vector<u8>,
- proof_of_possession: vector<u8>,
) acquires StakePool, ValidatorConfig {
- rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, proof_of_possession, false);
+ rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, false);
}
@@ -3982,17 +3961,16 @@ Returns validator's next epoch voting power, including pending_active, active, a
### Function `initialize_validator`
-public entry fun initialize_validator(account: &signer, consensus_pubkey: vector<u8>, proof_of_possession: vector<u8>, network_addresses: vector<u8>, fullnode_addresses: vector<u8>)
+public entry fun initialize_validator(account: &signer, consensus_pubkey: vector<u8>, network_addresses: vector<u8>, fullnode_addresses: vector<u8>)
-let pubkey_from_pop = bls12381::spec_public_key_from_bytes_with_pop(
+let pubkey_from_pop = ed25519::spec_public_key_validate_internal(
consensus_pubkey,
- proof_of_possession_from_bytes(proof_of_possession)
);
-aborts_if !option::spec_is_some(pubkey_from_pop);
+aborts_if !pubkey_from_pop;
let addr = signer::address_of(account);
let post_addr = signer::address_of(account);
let allowed = global<AllowedValidators>(@aptos_framework);
@@ -4157,7 +4135,7 @@ Returns validator's next epoch voting power, including pending_active, active, a
### Function `rotate_consensus_key`
-public entry fun rotate_consensus_key(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>, proof_of_possession: vector<u8>)
+public entry fun rotate_consensus_key(operator: &signer, pool_address: address, new_consensus_pubkey: vector<u8>)
@@ -4168,11 +4146,10 @@ Returns validator's next epoch voting power, including pending_active, active, a
aborts_if !exists<StakePool>(pool_address);
aborts_if signer::address_of(operator) != pre_stake_pool.operator_address;
aborts_if !exists<ValidatorConfig>(pool_address);
-let pubkey_from_pop = bls12381::spec_public_key_from_bytes_with_pop(
+let pubkey_from_pop = ed25519::spec_public_key_validate_internal(
new_consensus_pubkey,
- proof_of_possession_from_bytes(proof_of_possession)
);
-aborts_if !option::spec_is_some(pubkey_from_pop);
+aborts_if !pubkey_from_pop;
modifies global<ValidatorConfig>(pool_address);
include StakedValueNochange;
ensures validator_info.consensus_pubkey == new_consensus_pubkey;
@@ -4922,74 +4899,4 @@ Returns validator's next epoch voting power, including pending_active, active, a
-
-
-
-
-
-schema ResourceRequirement {
- requires exists<AptosCoinCapabilities>(@aptos_framework);
- requires exists<ValidatorPerformance>(@aptos_framework);
- requires exists<ValidatorSet>(@aptos_framework);
- requires exists<StakingConfig>(@aptos_framework);
- requires exists<StakingRewardsConfig>(@aptos_framework) || !features::spec_periodical_reward_rate_decrease_enabled();
- requires exists<timestamp::CurrentTimeMicroseconds>(@aptos_framework);
- requires exists<ValidatorFees>(@aptos_framework);
-}
-
-
-
-
-
-
-
-
-fun spec_get_reward_rate_1(config: StakingConfig): num {
- if (features::spec_periodical_reward_rate_decrease_enabled()) {
- let epoch_rewards_rate = global<staking_config::StakingRewardsConfig>(@aptos_framework).rewards_rate;
- if (epoch_rewards_rate.value == 0) {
- 0
- } else {
- let denominator_0 = aptos_std::fixed_point64::spec_divide_u128(staking_config::MAX_REWARDS_RATE, epoch_rewards_rate);
- let denominator = if (denominator_0 > MAX_U64) {
- MAX_U64
- } else {
- denominator_0
- };
- let nominator = aptos_std::fixed_point64::spec_multiply_u128(denominator, epoch_rewards_rate);
- nominator
- }
- } else {
- config.rewards_rate
- }
-}
-
-
-
-
-
-
-
-
-fun spec_get_reward_rate_2(config: StakingConfig): num {
- if (features::spec_periodical_reward_rate_decrease_enabled()) {
- let epoch_rewards_rate = global<staking_config::StakingRewardsConfig>(@aptos_framework).rewards_rate;
- if (epoch_rewards_rate.value == 0) {
- 1
- } else {
- let denominator_0 = aptos_std::fixed_point64::spec_divide_u128(staking_config::MAX_REWARDS_RATE, epoch_rewards_rate);
- let denominator = if (denominator_0 > MAX_U64) {
- MAX_U64
- } else {
- denominator_0
- };
- denominator
- }
- } else {
- config.rewards_rate_denominator
- }
-}
-
-
-
[move-book]: https://aptos.dev/move/book/SUMMARY
diff --git a/aptos-move/framework/aptos-framework/sources/genesis.move b/aptos-move/framework/aptos-framework/sources/genesis.move
index 58c6e01c7d89e5..8cf494eb372952 100644
--- a/aptos-move/framework/aptos-framework/sources/genesis.move
+++ b/aptos-move/framework/aptos-framework/sources/genesis.move
@@ -365,7 +365,6 @@ module aptos_framework::genesis {
operator,
pool_address,
validator.consensus_pubkey,
- validator.proof_of_possession,
);
stake::update_network_and_fullnode_addresses(
operator,
diff --git a/aptos-move/framework/aptos-framework/sources/stake.move b/aptos-move/framework/aptos-framework/sources/stake.move
index 1df14c8d29635a..fd14dd339169d2 100644
--- a/aptos-move/framework/aptos-framework/sources/stake.move
+++ b/aptos-move/framework/aptos-framework/sources/stake.move
@@ -23,7 +23,7 @@ module aptos_framework::stake {
use std::option::{Self, Option};
use std::signer;
use std::vector;
- use aptos_std::bls12381;
+ use aptos_std::ed25519;
use aptos_std::math64::min;
use aptos_std::table::{Self, Table};
use aptos_framework::aptos_coin::AptosCoin;
@@ -494,17 +494,10 @@ module aptos_framework::stake {
public entry fun initialize_validator(
account: &signer,
consensus_pubkey: vector,
- proof_of_possession: vector,
network_addresses: vector,
fullnode_addresses: vector,
) acquires AllowedValidators {
// Checks the public key has a valid proof-of-possession to prevent rogue-key attacks.
- let pubkey_from_pop = &mut bls12381::public_key_from_bytes_with_pop(
- consensus_pubkey,
- &proof_of_possession_from_bytes(proof_of_possession)
- );
- assert!(option::is_some(pubkey_from_pop), error::invalid_argument(EINVALID_PUBLIC_KEY));
-
initialize_owner(account);
move_to(account, ValidatorConfig {
consensus_pubkey,
@@ -693,7 +686,6 @@ module aptos_framework::stake {
operator: &signer,
pool_address: address,
new_consensus_pubkey: vector,
- proof_of_possession: vector,
genesis: bool,
) acquires StakePool, ValidatorConfig {
assert_stake_pool_exists(pool_address);
@@ -704,16 +696,6 @@ module aptos_framework::stake {
let validator_info = borrow_global_mut(pool_address);
let old_consensus_pubkey = validator_info.consensus_pubkey;
// Checks the public key has a valid proof-of-possession to prevent rogue-key attacks.
- if (!genesis) {
- let pubkey_from_pop = &mut bls12381::public_key_from_bytes_with_pop(
- new_consensus_pubkey,
- &proof_of_possession_from_bytes(proof_of_possession)
- );
- assert!(option::is_some(pubkey_from_pop), error::invalid_argument(EINVALID_PUBLIC_KEY));
- } else {
- let pubkey = &mut bls12381::public_key_from_bytes(new_consensus_pubkey);
- assert!(option::is_some(pubkey), error::invalid_argument(EINVALID_PUBLIC_KEY));
- };
validator_info.consensus_pubkey = new_consensus_pubkey;
event::emit_event(
@@ -733,9 +715,8 @@ module aptos_framework::stake {
operator: &signer,
pool_address: address,
new_consensus_pubkey: vector,
- proof_of_poseesion: vector,
) acquires StakePool, ValidatorConfig {
- rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, proof_of_poseesion, true);
+ rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, true);
}
/// Rotate the consensus key of the validator, it'll take effect in next epoch.
@@ -743,9 +724,8 @@ module aptos_framework::stake {
operator: &signer,
pool_address: address,
new_consensus_pubkey: vector,
- proof_of_possession: vector,
) acquires StakePool, ValidatorConfig {
- rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, proof_of_possession, false);
+ rotate_consensus_key_internal(operator, pool_address, new_consensus_pubkey, false);
}
/// Update the network and full node addresses of the validator. This only takes effect in the next epoch.
@@ -1388,7 +1368,6 @@ module aptos_framework::stake {
#[test_only]
use aptos_framework::aptos_coin;
- use aptos_std::bls12381::proof_of_possession_from_bytes;
#[test_only]
use aptos_std::fixed_point64;
@@ -1405,15 +1384,13 @@ module aptos_framework::stake {
#[test_only]
public fun join_validator_set_for_test(
- pk: &bls12381::PublicKey,
- pop: &bls12381::ProofOfPossession,
+ pk: &ed25519::ValidatedPublicKey,
operator: &signer,
pool_address: address,
should_end_epoch: bool,
) acquires AptosCoinCapabilities, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees {
- let pk_bytes = bls12381::public_key_to_bytes(pk);
- let pop_bytes = bls12381::proof_of_possession_to_bytes(pop);
- rotate_consensus_key(operator, pool_address, pk_bytes, pop_bytes);
+ let pk_bytes = ed25519::validated_public_key_to_bytes(pk);
+ rotate_consensus_key(operator, pool_address, pk_bytes);
join_validator_set(operator, pool_address);
if (should_end_epoch) {
end_epoch();
@@ -1484,8 +1461,7 @@ module aptos_framework::stake {
#[test_only]
public fun initialize_test_validator(
- public_key: &bls12381::PublicKey,
- proof_of_possession: &bls12381::ProofOfPossession,
+ public_key: &ed25519::UnvalidatedPublicKey,
validator: &signer,
amount: u64,
should_join_validator_set: bool,
@@ -1496,9 +1472,8 @@ module aptos_framework::stake {
account::create_account_for_test(validator_address);
};
- let pk_bytes = bls12381::public_key_to_bytes(public_key);
- let pop_bytes = bls12381::proof_of_possession_to_bytes(proof_of_possession);
- initialize_validator(validator, pk_bytes, pop_bytes, vector::empty(), vector::empty());
+ let pk_bytes = ed25519::unvalidated_public_key_to_bytes(public_key);
+ initialize_validator(validator, pk_bytes, vector::empty(), vector::empty());
if (amount > 0) {
mint_and_add_stake(validator, amount);
@@ -1516,7 +1491,7 @@ module aptos_framework::stake {
public fun create_validator_set(
aptos_framework: &signer,
active_validator_addresses: vector,
- public_keys: vector,
+ public_keys: vector,
) {
let active_validators = vector::empty();
let i = 0;
@@ -1527,7 +1502,7 @@ module aptos_framework::stake {
addr: *validator_address,
voting_power: 0,
config: ValidatorConfig {
- consensus_pubkey: bls12381::public_key_to_bytes(pk),
+ consensus_pubkey: ed25519::validated_public_key_to_bytes(pk),
network_addresses: b"",
fullnode_addresses: b"",
validator_index: 0,
@@ -1574,11 +1549,10 @@ module aptos_framework::stake {
}
#[test_only]
- public fun generate_identity(): (bls12381::SecretKey, bls12381::PublicKey, bls12381::ProofOfPossession) {
- let (sk, pkpop) = bls12381::generate_keys();
- let pop = bls12381::generate_proof_of_possession(&sk);
- let unvalidated_pk = bls12381::public_key_with_pop_to_normal(&pkpop);
- (sk, unvalidated_pk, pop)
+ public fun generate_identity(): (ed25519::SecretKey, ed25519::UnvalidatedPublicKey) {
+ let (sk, pkpop) = ed25519::generate_keys();
+ let unvalidated_pk = ed25519::public_key_to_unvalidated(&pkpop);
+ (sk, unvalidated_pk)
}
#[test(aptos_framework = @aptos_framework, validator = @0x123)]
@@ -1588,8 +1562,8 @@ module aptos_framework::stake {
validator: &signer,
) acquires AllowedValidators, AptosCoinCapabilities, OwnerCapability, StakePool, ValidatorConfig, ValidatorPerformance, ValidatorSet, ValidatorFees {
initialize_for_test(aptos_framework);
- let (_sk, pk, pop) = generate_identity();
- initialize_test_validator(&pk, &pop, validator, 100, false, false);
+ let (_sk, pk) = generate_identity();
+ initialize_test_validator(&pk, validator, 100, false, false);
// Add more stake to exceed max. This should fail.
mint_and_add_stake(validator, 9901);
diff --git a/aptos-move/framework/aptos-framework/sources/stake.spec.move b/aptos-move/framework/aptos-framework/sources/stake.spec.move
index 64e229f81bd227..9018ea92127898 100644
--- a/aptos-move/framework/aptos-framework/sources/stake.spec.move
+++ b/aptos-move/framework/aptos-framework/sources/stake.spec.move
@@ -104,15 +104,13 @@ spec aptos_framework::stake {
spec initialize_validator(
account: &signer,
consensus_pubkey: vector,
- proof_of_possession: vector,
network_addresses: vector,
fullnode_addresses: vector,
){
- let pubkey_from_pop = bls12381::spec_public_key_from_bytes_with_pop(
+ let pubkey_from_pop = ed25519::spec_public_key_validate_internal(
consensus_pubkey,
- proof_of_possession_from_bytes(proof_of_possession)
);
- aborts_if !option::spec_is_some(pubkey_from_pop);
+ aborts_if !pubkey_from_pop;
let addr = signer::address_of(account);
let post_addr = signer::address_of(account);
let allowed = global(@aptos_framework);
@@ -357,18 +355,16 @@ spec aptos_framework::stake {
operator: &signer,
pool_address: address,
new_consensus_pubkey: vector,
- proof_of_possession: vector,
) {
let pre_stake_pool = global(pool_address);
let post validator_info = global(pool_address);
aborts_if !exists(pool_address);
aborts_if signer::address_of(operator) != pre_stake_pool.operator_address;
aborts_if !exists(pool_address);
- let pubkey_from_pop = bls12381::spec_public_key_from_bytes_with_pop(
+ let pubkey_from_pop = ed25519::spec_public_key_validate_internal(
new_consensus_pubkey,
- proof_of_possession_from_bytes(proof_of_possession)
);
- aborts_if !option::spec_is_some(pubkey_from_pop);
+ aborts_if !pubkey_from_pop;
modifies global(pool_address);
include StakedValueNochange;
diff --git a/aptos-move/framework/aptos-stdlib/doc/ed25519.md b/aptos-move/framework/aptos-stdlib/doc/ed25519.md
index ed3bb72bd34fec..68fe0b4704df36 100644
--- a/aptos-move/framework/aptos-stdlib/doc/ed25519.md
+++ b/aptos-move/framework/aptos-stdlib/doc/ed25519.md
@@ -175,32 +175,32 @@ A purported Ed25519 signature that can be verified via signature_verify_st
## Constants
-
+
-The size of a serialized public key, in bytes.
+Wrong number of bytes were given as input when deserializing an Ed25519 public key.
-const PUBLIC_KEY_NUM_BYTES: u64 = 32;
+const E_WRONG_PUBKEY_SIZE: u64 = 1;
-
+
-Wrong number of bytes were given as input when deserializing an Ed25519 public key.
+Wrong number of bytes were given as input when deserializing an Ed25519 signature.
-const E_WRONG_PUBKEY_SIZE: u64 = 1;
+const E_WRONG_SIGNATURE_SIZE: u64 = 2;
-
+
-Wrong number of bytes were given as input when deserializing an Ed25519 signature.
+The size of a serialized public key, in bytes.
-const E_WRONG_SIGNATURE_SIZE: u64 = 2;
+const PUBLIC_KEY_NUM_BYTES: u64 = 32;
diff --git a/aptos-move/framework/aptos-stdlib/doc/overview.md b/aptos-move/framework/aptos-stdlib/doc/overview.md
index 6176385db1d977..25ff7563d13dca 100644
--- a/aptos-move/framework/aptos-stdlib/doc/overview.md
+++ b/aptos-move/framework/aptos-stdlib/doc/overview.md
@@ -15,8 +15,6 @@ This is the reference documentation of the Aptos standard library.
- [`0x1::any`](any.md#0x1_any)
- [`0x1::aptos_hash`](hash.md#0x1_aptos_hash)
- [`0x1::big_vector`](big_vector.md#0x1_big_vector)
-- [`0x1::bls12381`](bls12381.md#0x1_bls12381)
-- [`0x1::bls12381_algebra`](bls12381_algebra.md#0x1_bls12381_algebra)
- [`0x1::bn254_algebra`](bn254_algebra.md#0x1_bn254_algebra)
- [`0x1::capability`](capability.md#0x1_capability)
- [`0x1::comparator`](comparator.md#0x1_comparator)
diff --git a/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381.move b/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381.move
deleted file mode 100644
index de7d05ad8b18b7..00000000000000
--- a/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381.move
+++ /dev/null
@@ -1,985 +0,0 @@
-/// Contains functions for:
-///
-/// The minimum-pubkey-size variant of [Boneh-Lynn-Shacham (BLS) signatures](https://en.wikipedia.org/wiki/BLS_digital_signature),
-/// where public keys are BLS12-381 elliptic-curve points in $\mathbb{G}_1$ and signatures are in $\mathbb{G}_2$,
-/// as per the [IETF BLS draft standard](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-bls-signature#section-2.1).
-
-module aptos_std::bls12381 {
- use std::option::{Self, Option};
- #[test_only]
- use std::error::invalid_argument;
-
- /// The signature size, in bytes
- const SIGNATURE_SIZE: u64 = 96;
-
- /// The public key size, in bytes
- const PUBLIC_KEY_NUM_BYTES: u64 = 48;
-
- /// The caller was supposed to input one or more public keys.
- const EZERO_PUBKEYS: u64 = 1;
-
- /// One of the given inputs has the wrong size.s
- const EWRONG_SIZE: u64 = 2;
-
- /// The number of signers does not match the number of messages to be signed.
- const E_NUM_SIGNERS_MUST_EQ_NUM_MESSAGES: u64 = 3;
-
- // TODO: Performance would increase if structs in this module are implemented natively via handles (similar to Table and
- // RistrettoPoint). This will avoid unnecessary (de)serialization. We would need to allow storage of these structs too.
-
- #[test_only]
- struct SecretKey has copy, drop {
- bytes: vector,
- }
-
- /// A *validated* public key that:
- /// (1) is a point in the prime-order subgroup of the BLS12-381 elliptic curve, and
- /// (2) is not the identity point
- ///
- /// This struct can be used to verify a normal (non-aggregated) signature.
- ///
- /// This struct can be combined with a ProofOfPossession struct in order to create a PublicKeyWithPop struct, which
- /// can be used to verify a multisignature.
- struct PublicKey has copy, drop, store {
- bytes: vector
- }
-
- /// A proof-of-possession (PoP).
- /// Given such a struct and a PublicKey struct, one can construct a PublicKeyWithPoP (see below).
- struct ProofOfPossession has copy, drop, store {
- bytes: vector
- }
-
- /// A *validated* public key that had a successfully-verified proof-of-possession (PoP).
- ///
- /// A vector of these structs can be either:
- /// (1) used to verify an aggregate signature
- /// (2) aggregated with other PublicKeyWithPoP structs into an AggrPublicKeysWithPoP, which in turn can be used
- /// to verify a multisignature
- struct PublicKeyWithPoP has copy, drop, store {
- bytes: vector
- }
-
- /// An aggregation of public keys with verified PoPs, which can be used to verify multisignatures.
- struct AggrPublicKeysWithPoP has copy, drop, store {
- bytes: vector
- }
-
- /// A BLS signature. This can be either a:
- /// (1) normal (non-aggregated) signature
- /// (2) signature share (for a multisignature or aggregate signature)
- struct Signature has copy, drop, store {
- bytes: vector
- }
-
- /// An aggregation of BLS signatures. This can be either a:
- /// (4) aggregated signature (i.e., an aggregation of signatures s_i, each on a message m_i)
- /// (3) multisignature (i.e., an aggregation of signatures s_i, each on the same message m)
- ///
- /// We distinguish between a Signature type and a AggrOrMultiSignature type to prevent developers from interchangeably
- /// calling `verify_multisignature` and `verify_signature_share` to verify both multisignatures and signature shares,
- /// which could create problems down the line.
- struct AggrOrMultiSignature has copy, drop, store {
- bytes: vector
- }
-
- /// Creates a new public key from a sequence of bytes.
- public fun public_key_from_bytes(bytes: vector): Option {
- if (validate_pubkey_internal(bytes)) {
- option::some(PublicKey {
- bytes
- })
- } else {
- option::none()
- }
- }
-
- /// Serializes a public key into 48 bytes.
- public fun public_key_to_bytes(pk: &PublicKey): vector {
- pk.bytes
- }
-
- /// Creates a new proof-of-possession (PoP) which can be later used to create a PublicKeyWithPoP struct,
- public fun proof_of_possession_from_bytes(bytes: vector): ProofOfPossession {
- ProofOfPossession {
- bytes
- }
- }
-
- /// Serializes the signature into 96 bytes.
- public fun proof_of_possession_to_bytes(pop: &ProofOfPossession): vector {
- pop.bytes
- }
-
- /// Creates a PoP'd public key from a normal public key and a corresponding proof-of-possession.
- public fun public_key_from_bytes_with_pop(pk_bytes: vector, pop: &ProofOfPossession): Option {
- if (verify_proof_of_possession_internal(pk_bytes, pop.bytes)) {
- option::some(PublicKeyWithPoP {
- bytes: pk_bytes
- })
- } else {
- option::none()
- }
- }
-
- /// Creates a normal public key from a PoP'd public key.
- public fun public_key_with_pop_to_normal(pkpop: &PublicKeyWithPoP): PublicKey {
- PublicKey {
- bytes: pkpop.bytes
- }
- }
-
- /// Serializes a PoP'd public key into 48 bytes.
- public fun public_key_with_pop_to_bytes(pk: &PublicKeyWithPoP): vector {
- pk.bytes
- }
-
- /// Creates a new signature from a sequence of bytes. Does not check the signature for prime-order subgroup
- /// membership since that is done implicitly during verification.
- public fun signature_from_bytes(bytes: vector): Signature {
- Signature {
- bytes
- }
- }
-
- /// Serializes the signature into 96 bytes.
- public fun signature_to_bytes(sig: &Signature): vector {
- sig.bytes
- }
-
- /// Checks that the group element that defines a signature is in the prime-order subgroup.
- /// This check is implicitly performed when verifying any signature via this module, but we expose this functionality
- /// in case it might be useful for applications to easily dismiss invalid signatures early on.
- public fun signature_subgroup_check(signature: &Signature): bool {
- signature_subgroup_check_internal(signature.bytes)
- }
-
- /// Given a vector of public keys with verified PoPs, combines them into an *aggregated* public key which can be used
- /// to verify multisignatures using `verify_multisignature` and aggregate signatures using `verify_aggregate_signature`.
- /// Aborts if no public keys are given as input.
- public fun aggregate_pubkeys(public_keys: vector): AggrPublicKeysWithPoP {
- let (bytes, success) = aggregate_pubkeys_internal(public_keys);
- assert!(success, std::error::invalid_argument(EZERO_PUBKEYS));
-
- AggrPublicKeysWithPoP {
- bytes
- }
- }
-
- /// Serializes an aggregate public key into 48 bytes.
- public fun aggregate_pubkey_to_bytes(apk: &AggrPublicKeysWithPoP): vector {
- apk.bytes
- }
-
- /// Aggregates the input signatures into an aggregate-or-multi-signature structure, which can be later verified via
- /// `verify_aggregate_signature` or `verify_multisignature`. Returns `None` if zero signatures are given as input
- /// or if some of the signatures are not valid group elements.
- public fun aggregate_signatures(signatures: vector): Option {
- let (bytes, success) = aggregate_signatures_internal(signatures);
- if (success) {
- option::some(
- AggrOrMultiSignature {
- bytes
- }
- )
- } else {
- option::none()
- }
- }
-
- /// Serializes an aggregate-or-multi-signature into 96 bytes.
- public fun aggr_or_multi_signature_to_bytes(sig: &AggrOrMultiSignature): vector {
- sig.bytes
- }
-
- /// Deserializes an aggregate-or-multi-signature from 96 bytes.
- public fun aggr_or_multi_signature_from_bytes(bytes: vector): AggrOrMultiSignature {
- assert!(std::vector::length(&bytes) == SIGNATURE_SIZE, std::error::invalid_argument(EWRONG_SIZE));
-
- AggrOrMultiSignature {
- bytes
- }
- }
-
-
- /// Checks that the group element that defines an aggregate-or-multi-signature is in the prime-order subgroup.
- public fun aggr_or_multi_signature_subgroup_check(signature: &AggrOrMultiSignature): bool {
- signature_subgroup_check_internal(signature.bytes)
- }
-
- /// Verifies an aggregate signature, an aggregation of many signatures `s_i`, each on a different message `m_i`.
- public fun verify_aggregate_signature(
- aggr_sig: &AggrOrMultiSignature,
- public_keys: vector,
- messages: vector>,
- ): bool {
- verify_aggregate_signature_internal(aggr_sig.bytes, public_keys, messages)
- }
-
- /// Verifies a multisignature: an aggregation of many signatures, each on the same message `m`.
- public fun verify_multisignature(
- multisig: &AggrOrMultiSignature,
- aggr_public_key: &AggrPublicKeysWithPoP,
- message: vector
- ): bool {
- verify_multisignature_internal(multisig.bytes, aggr_public_key.bytes, message)
- }
-
- /// Verifies a normal, non-aggregated signature.
- public fun verify_normal_signature(
- signature: &Signature,
- public_key: &PublicKey,
- message: vector
- ): bool {
- verify_normal_signature_internal(signature.bytes, public_key.bytes, message)
- }
-
- /// Verifies a signature share in the multisignature share or an aggregate signature share.
- public fun verify_signature_share(
- signature_share: &Signature,
- public_key: &PublicKeyWithPoP,
- message: vector
- ): bool {
- verify_signature_share_internal(signature_share.bytes, public_key.bytes, message)
- }
-
- #[test_only]
- /// Generates a BLS key-pair: a secret key with its corresponding public key.
- public fun generate_keys(): (SecretKey, PublicKeyWithPoP) {
- let (sk_bytes, pk_bytes) = generate_keys_internal();
- let sk = SecretKey {
- bytes: sk_bytes
- };
- let pkpop = PublicKeyWithPoP {
- bytes: pk_bytes
- };
- (sk, pkpop)
- }
-
- #[test_only]
- /// Generates a BLS signature for a message with a signing key.
- public fun sign_arbitrary_bytes(signing_key: &SecretKey, message: vector): Signature {
- Signature {
- bytes: sign_internal(signing_key.bytes, message)
- }
- }
-
- #[test_only]
- /// Generates a multi-signature for a message with multiple signing keys.
- public fun multi_sign_arbitrary_bytes(signing_keys: &vector, message: vector): AggrOrMultiSignature {
- let n = std::vector::length(signing_keys);
- let sigs = vector[];
- let i: u64 = 0;
- while (i < n) {
- let sig = sign_arbitrary_bytes(std::vector::borrow(signing_keys, i), message);
- std::vector::push_back(&mut sigs, sig);
- i = i + 1;
- };
- let multisig = aggregate_signatures(sigs);
- option::extract(&mut multisig)
- }
-
- #[test_only]
- /// Generates an aggregated signature over all messages in messages, where signing_keys[i] signs messages[i].
- public fun aggr_sign_arbitrary_bytes(signing_keys: &vector, messages: &vector>): AggrOrMultiSignature {
- let signing_key_count = std::vector::length(signing_keys);
- let message_count = std::vector::length(messages);
- assert!(signing_key_count == message_count, invalid_argument(E_NUM_SIGNERS_MUST_EQ_NUM_MESSAGES));
- let sigs = vector[];
- let i: u64 = 0;
- while (i < signing_key_count) {
- let sig = sign_arbitrary_bytes(std::vector::borrow(signing_keys, i), *std::vector::borrow(messages, i));
- std::vector::push_back(&mut sigs, sig);
- i = i + 1;
- };
- let aggr_sig = aggregate_signatures(sigs);
- option::extract(&mut aggr_sig)
- }
-
- #[test_only]
- /// Returns a mauled copy of a byte array.
- public fun maul_bytes(bytes: &vector): vector {
- let new_bytes = *bytes;
- let first_byte = std::vector::borrow_mut(&mut new_bytes, 0);
- *first_byte = *first_byte ^ 0xff;
- new_bytes
- }
-
- #[test_only]
- /// Returns a mauled copy of a normal signature.
- public fun maul_signature(sig: &Signature): Signature {
- Signature {
- bytes: maul_bytes(&signature_to_bytes(sig))
- }
- }
-
- #[test_only]
- /// Returns a mauled copy of an aggregated signature or a multi-signature.
- public fun maul_aggr_or_multi_signature(sig: &AggrOrMultiSignature): AggrOrMultiSignature {
- AggrOrMultiSignature {
- bytes: maul_bytes(&aggr_or_multi_signature_to_bytes(sig))
- }
- }
-
- #[test_only]
- /// Returns a mauled copy of a normal public key.
- public fun maul_public_key(pk: &PublicKey): PublicKey {
- PublicKey {
- bytes: maul_bytes(&public_key_to_bytes(pk))
- }
- }
-
- #[test_only]
- /// Returns a mauled copy of a PoP'd public key.
- public fun maul_public_key_with_pop(pk: &PublicKeyWithPoP): PublicKeyWithPoP {
- PublicKeyWithPoP {
- bytes: maul_bytes(&public_key_with_pop_to_bytes(pk))
- }
- }
-
- #[test_only]
- /// Returns a mauled copy of an aggregated public key.
- public fun maul_aggregated_public_key(pk: &AggrPublicKeysWithPoP): AggrPublicKeysWithPoP {
- AggrPublicKeysWithPoP {
- bytes: maul_bytes(&aggregate_pubkey_to_bytes(pk))
- }
- }
-
- #[test_only]
- /// Returns a mauled copy of a proof-of-possession.
- public fun maul_proof_of_possession(pop: &ProofOfPossession): ProofOfPossession {
- ProofOfPossession {
- bytes: maul_bytes(&proof_of_possession_to_bytes(pop))
- }
- }
-
-
- #[test_only]
- /// Generates a proof-of-possession (PoP) for the public key associated with the secret key `sk`.
- public fun generate_proof_of_possession(sk: &SecretKey): ProofOfPossession {
- ProofOfPossession {
- bytes: generate_proof_of_possession_internal(sk.bytes)
- }
- }
-
- //
- // Native functions
- //
-
- /// CRYPTOGRAPHY WARNING: This function assumes that the caller verified all public keys have a valid
- /// proof-of-possesion (PoP) using `verify_proof_of_possession`.
- ///
- /// Given a vector of serialized public keys, combines them into an aggregated public key, returning `(bytes, true)`,
- /// where `bytes` store the serialized public key.
- /// Aborts if no public keys are given as input.
- native fun aggregate_pubkeys_internal(public_keys: vector): (vector, bool);
-
-
- /// CRYPTOGRAPHY WARNING: This function can be safely called without verifying that the input signatures are elements
- /// of the prime-order subgroup of the BLS12-381 curve.
- ///
- /// Given a vector of serialized signatures, combines them into an aggregate signature, returning `(bytes, true)`,
- /// where `bytes` store the serialized signature.
- /// Does not check the input signatures nor the final aggregated signatures for prime-order subgroup membership.
- /// Returns `(_, false)` if no signatures are given as input.
- /// Does not abort.
- native fun aggregate_signatures_internal(signatures: vector): (vector, bool);
-
- /// Return `true` if the bytes in `public_key` are a valid BLS12-381 public key:
- /// (1) it is NOT the identity point, and
- /// (2) it is a BLS12-381 elliptic curve point, and
- /// (3) it is a prime-order point
- /// Return `false` otherwise.
- /// Does not abort.
- native fun validate_pubkey_internal(public_key: vector): bool;
-
- /// Return `true` if the elliptic curve point serialized in `signature`:
- /// (1) is NOT the identity point, and
- /// (2) is a BLS12-381 elliptic curve point, and
- /// (3) is a prime-order point
- /// Return `false` otherwise.
- /// Does not abort.
- native fun signature_subgroup_check_internal(signature: vector): bool;
-
- /// CRYPTOGRAPHY WARNING: First, this function assumes all public keys have a valid proof-of-possesion (PoP).
- /// This prevents both small-subgroup attacks and rogue-key attacks. Second, this function can be safely called
- /// without verifying that the aggregate signature is in the prime-order subgroup of the BLS12-381 curve.
- ///
- /// Returns `true` if the aggregate signature `aggsig` on `messages` under `public_keys` verifies (where `messages[i]`
- /// should be signed by `public_keys[i]`).
- ///
- /// Returns `false` if either:
- /// - no public keys or messages are given as input,
- /// - number of messages does not equal number of public keys
- /// - `aggsig` (1) is the identity point, or (2) is NOT a BLS12-381 elliptic curve point, or (3) is NOT a
- /// prime-order point
- /// Does not abort.
- native fun verify_aggregate_signature_internal(
- aggsig: vector,
- public_keys: vector,
- messages: vector>,
- ): bool;
-
- /// CRYPTOGRAPHY WARNING: This function assumes verified proofs-of-possesion (PoP) for the public keys used in
- /// computing the aggregate public key. This prevents small-subgroup attacks and rogue-key attacks.
- ///
- /// Return `true` if the BLS `multisignature` on `message` verifies against the BLS aggregate public key `agg_public_key`.
- /// Returns `false` otherwise.
- /// Does not abort.
- native fun verify_multisignature_internal(
- multisignature: vector,
- agg_public_key: vector,
- message: vector
- ): bool;
-
- /// CRYPTOGRAPHY WARNING: This function WILL check that the public key is a prime-order point, in order to prevent
- /// library users from misusing the library by forgetting to validate public keys before giving them as arguments to
- /// this function.
- ///
- /// Returns `true` if the `signature` on `message` verifies under `public key`.
- /// Returns `false` otherwise.
- /// Does not abort.
- native fun verify_normal_signature_internal(
- signature: vector,
- public_key: vector,
- message: vector
- ): bool;
-
- /// Return `true` if the bytes in `public_key` are a valid bls12381 public key (as per `validate_pubkey`)
- /// *and* this public key has a valid proof-of-possesion (PoP).
- /// Return `false` otherwise.
- /// Does not abort.
- native fun verify_proof_of_possession_internal(
- public_key: vector,
- proof_of_possesion: vector
- ): bool;
-
- /// CRYPTOGRAPHY WARNING: Assumes the public key has a valid proof-of-possesion (PoP). This prevents rogue-key
- /// attacks later on during signature aggregation.
- ///
- /// Returns `true` if the `signature_share` on `message` verifies under `public key`.
- /// Returns `false` otherwise, similar to `verify_multisignature`.
- /// Does not abort.
- native fun verify_signature_share_internal(
- signature_share: vector,
- public_key: vector,
- message: vector
- ): bool;
-
- #[test_only]
- native fun generate_keys_internal(): (vector, vector);
-
- #[test_only]
- native fun sign_internal(sk: vector, msg: vector): vector;
-
- #[test_only]
- native fun generate_proof_of_possession_internal(sk: vector): vector;
-
- //
- // Constants and helpers for tests
- //
-
- /// Random signature generated by running `cargo test -- bls12381_sample_signature --nocapture --include-ignored` in `crates/aptos-crypto`.
- /// The message signed is "Hello Aptos!" and the associated SK is 07416693b6b32c84abe45578728e2379f525729e5b94762435a31e65ecc728da.
- const RANDOM_SIGNATURE: vector = x"a01a65854f987d3434149b7f08f70730e30b241984e8712bc2aca885d632aafced4c3f661209debb6b1c8601326623cc16ca2f6c9edc53b7b88b7435fb6b05ddece418d2c34dc6aca2f5a11a79e67774582c14084a01dcb7820e4cb4bad0ea8d";
-
- /// Random signature generated by running `cargo test -- bls12381_sample_signature --nocapture --include-ignored` in `crates/aptos-crypto`.
- /// The associated SK is 07416693b6b32c84abe45578728e2379f525729e5b94762435a31e65ecc728da.
- const RANDOM_PK: vector = x"8a53e7ae5270e3e765cd8a4032c2e77c6f7e87a44ebb85bf28a4d7865565698f975346714262f9e47c6f3e0d5d951660";
-
- //
- // Tests
- //
-
- #[test_only]
- fun get_random_aggsig(): AggrOrMultiSignature {
- assert!(signature_subgroup_check_internal(RANDOM_SIGNATURE), 1);
-
- AggrOrMultiSignature { bytes: RANDOM_SIGNATURE }
- }
-
- #[test_only]
- fun get_random_pk_with_pop(): PublicKeyWithPoP {
- assert!(validate_pubkey_internal(RANDOM_PK), 1);
-
- PublicKeyWithPoP {
- bytes: RANDOM_PK
- }
- }
-
- #[test]
- fun test_pubkey_validation() {
- // test low order points (in group for PK)
- assert!(option::is_none(&public_key_from_bytes(x"ae3cd9403b69c20a0d455fd860e977fe6ee7140a7f091f26c860f2caccd3e0a7a7365798ac10df776675b3a67db8faa0")), 1);
- assert!(option::is_none(&public_key_from_bytes(x"928d4862a40439a67fd76a9c7560e2ff159e770dcf688ff7b2dd165792541c88ee76c82eb77dd6e9e72c89cbf1a56a68")), 1);
- assert!(option::is_some(&public_key_from_bytes(x"b3e4921277221e01ed71284be5e3045292b26c7f465a6fcdba53ee47edd39ec5160da3b229a73c75671024dcb36de091")), 1);
- }
-
- #[test]
- #[expected_failure(abort_code = 65537, location = Self)]
- fun test_empty_pubkey_aggregation() {
- // First, make sure if no inputs are given, the function returns None
- // assert!(aggregate_pop_verified_pubkeys(vector::empty()) == option::none(), 1);
- aggregate_pubkeys(std::vector::empty());
- }
-
- #[test]
- fun test_pubkey_aggregation() {
- // Second, try some test-cases generated by running the following command in `crates/aptos-crypto`:
- // $ cargo test -- sample_aggregate_pk_and_multisig --nocapture --include-ignored
- let pks = vector[
- PublicKeyWithPoP { bytes: x"92e201a806af246f805f460fbdc6fc90dd16a18d6accc236e85d3578671d6f6690dde22134d19596c58ce9d63252410a" },
- PublicKeyWithPoP { bytes: x"ab9df801c6f96ade1c0490c938c87d5bcc2e52ccb8768e1b5d14197c5e8bfa562783b96711b702dda411a1a9f08ebbfa" },
- PublicKeyWithPoP { bytes: x"b698c932cf7097d99c17bd6e9c9dc4eeba84278c621700a8f80ec726b1daa11e3ab55fc045b4dbadefbeef05c4182494" },
- PublicKeyWithPoP { bytes: x"934706a8b876d47a996d427e1526ce52c952d5ec0858d49cd262efb785b62b1972d06270b0a7adda1addc98433ad1843" },
- PublicKeyWithPoP { bytes: x"a4cd352daad3a0651c1998dfbaa7a748e08d248a54347544bfedd51a197e016bb6008e9b8e45a744e1a030cc3b27d2da" },
- ];
-
- // agg_pks[i] = \sum_{j <= i} pk[j]
- let agg_pks = vector[
- AggrPublicKeysWithPoP { bytes: x"92e201a806af246f805f460fbdc6fc90dd16a18d6accc236e85d3578671d6f6690dde22134d19596c58ce9d63252410a" },
- AggrPublicKeysWithPoP { bytes: x"b79ad47abb441d7eda9b220a626df2e4e4910738c5f777947f0213398ecafae044ec0c20d552d1348347e9abfcf3eca1" },
- AggrPublicKeysWithPoP { bytes: x"b5f5eb6153ab5388a1a76343d714e4a2dcf224c5d0722d1e8e90c6bcead05c573fffe986460bd4000645a655bf52bc60" },
- AggrPublicKeysWithPoP { bytes: x"b922006ec14c183572a8864c31dc6632dccffa9f9c86411796f8b1b5a93a2457762c8e2f5ef0a2303506c4bca9a4e0bf" },
- AggrPublicKeysWithPoP { bytes: x"b53df1cfee2168f59e5792e710bf22928dc0553e6531dae5c7656c0a66fc12cb82fbb04863938c953dc901a5a79cc0f3" },
- ];
-
- let i = 0;
- let accum_pk = std::vector::empty();
- while (i < std::vector::length(&pks)) {
- std::vector::push_back(&mut accum_pk, *std::vector::borrow(&pks, i));
-
- let apk = aggregate_pubkeys(accum_pk);
-
- // Make sure PKs were aggregated correctly
- assert!(apk == *std::vector::borrow(&agg_pks, i), 1);
- assert!(validate_pubkey_internal(apk.bytes), 1);
-
- i = i + 1;
- };
- }
-
- #[test]
- fun test_pubkey_validation_against_invalid_keys() {
- let (_sk, pk) = generate_keys();
- let pk_bytes = public_key_with_pop_to_bytes(&pk);
- assert!(option::is_some(&public_key_from_bytes(pk_bytes)), 1);
- assert!(option::is_none(&public_key_from_bytes(maul_bytes(&pk_bytes))), 1);
- }
-
- #[test]
- fun test_signature_aggregation() {
- // First, test empty aggregation
- assert!(option::is_none(&mut aggregate_signatures(vector[])), 1);
-
- // Second, try some test-cases generated by running the following command in `crates/aptos-crypto`:
- // $ cargo test -- sample_aggregate_sigs --nocapture --include-ignored
-
- // Signatures of each signer i
- let sigs = vector[
- signature_from_bytes(x"a55ac2d64b4c1d141b15d876d3e54ad1eea07ee488e8287cce7cdf3eec551458ab5795ab196f8c112590346f7bc7c97e0053cd5be0f9bd74b93a87cd44458e98d125d6d5c6950ea5e62666beb34422ead79121f8cb0815dae41a986688d03eaf"),
- signature_from_bytes(x"90a639a44491191c46379a843266c293de3a46197714ead2ad3886233dd5c2b608b6437fa32fbf9d218b20f1cbfa7970182663beb9c148e2e9412b148e16abf283ffa51b8a536c0e55d61b2e5c849edc49f636c0ef07cb99f125cbcf602e22bb"),
- signature_from_bytes(x"9527d81aa15863ef3a3bf96bea6d58157d5063a93a6d0eb9d8b4f4bbda3b31142ec4586cb519da2cd7600941283d1bad061b5439703fd584295b44037a969876962ae1897dcc7cadf909d06faae213c4fef8e015dfb33ec109af02ab0c3f6833"),
- signature_from_bytes(x"a54d264f5cab9654b1744232c4650c42b29adf2b19bd00bbdaf4a4d792ee4dfd40a1fe1b067f298bcfd8ae4fdc8250660a2848bd4a80d96585afccec5c6cfa617033dd7913c9acfdf98a72467e8a5155d4cad589a72d6665be7cb410aebc0068"),
- signature_from_bytes(x"8d22876bdf73e6ad36ed98546018f6258cd47e45904b87c071e774a6ef4b07cac323258cb920b2fe2b07cca1f2b24bcb0a3194ec76f32edb92391ed2c39e1ada8919f8ea755c5e39873d33ff3a8f4fba21b1261c1ddb9d1688c2b40b77e355d1"),
- ];
-
- // multisigs[i] is a signature on "Hello, Aptoverse!" from signers 1 through i (inclusive)
- let multisigs = vector[
- AggrOrMultiSignature { bytes: x"a55ac2d64b4c1d141b15d876d3e54ad1eea07ee488e8287cce7cdf3eec551458ab5795ab196f8c112590346f7bc7c97e0053cd5be0f9bd74b93a87cd44458e98d125d6d5c6950ea5e62666beb34422ead79121f8cb0815dae41a986688d03eaf" },
- AggrOrMultiSignature { bytes: x"8f1949a06b95c3cb62898d861f889350c0d2cb740da513bfa195aa0ab8fa006ea2efe004a7bbbd9bb363637a279aed20132efd0846f520e7ee0e8ed847a1c6969bb986ad2239bcc9af561b6c2aa6d3016e1c722146471f1e28313de189fe7ebc" },
- AggrOrMultiSignature { bytes: x"ab5ad42bb8f350f8a6b4ae897946a05dbe8f2b22db4f6c37eff6ff737aebd6c5d75bd1abdfc99345ac8ec38b9a449700026f98647752e1c99f69bb132340f063b8a989728e0a3d82a753740bf63e5d8f51e413ebd9a36f6acbe1407a00c4b3e7" },
- AggrOrMultiSignature { bytes: x"ae307a0d055d3ba55ad6ec7094adef27ed821bdcf735fb509ab2c20b80952732394bc67ea1fd8c26ea963540df7448f8102509f7b8c694e4d75f30a43c455f251b6b3fd8b580b9228ffeeb9039834927aacefccd3069bef4b847180d036971cf" },
- AggrOrMultiSignature { bytes: x"8284e4e3983f29cb45020c3e2d89066df2eae533a01cb6ca2c4d466b5e02dd22467f59640aa120db2b9cc49e931415c3097e3d54ff977fd9067b5bc6cfa1c885d9d8821aef20c028999a1d97e783ae049d8fa3d0bbac36ce4ca8e10e551d3461" },
- ];
-
- let i = 0;
- let accum_sigs = std::vector::empty();
- while (i < std::vector::length(&sigs)) {
- std::vector::push_back(&mut accum_sigs, *std::vector::borrow(&sigs, i));
-
- let multisig = option::extract(&mut aggregate_signatures(accum_sigs));
-
- // Make sure sigs were aggregated correctly
- assert!(multisig == *std::vector::borrow(&multisigs, i), 1);
- assert!(signature_subgroup_check_internal(multisig.bytes), 1);
-
- i = i + 1;
- };
- }
-
- #[test]
- fun test_empty_signature_aggregation() {
- assert!(option::is_none(&mut aggregate_signatures(vector[])), 1);
- }
-
- #[test]
- fun test_verify_multisig() {
- // Second, try some test-cases generated by running the following command in `crates/aptos-crypto`:
- // $ cargo test -- sample_aggregate_pk_and_multisig --nocapture --include-ignored
- let pks = vector[
- PublicKeyWithPoP { bytes: x"92e201a806af246f805f460fbdc6fc90dd16a18d6accc236e85d3578671d6f6690dde22134d19596c58ce9d63252410a" },
- PublicKeyWithPoP { bytes: x"ab9df801c6f96ade1c0490c938c87d5bcc2e52ccb8768e1b5d14197c5e8bfa562783b96711b702dda411a1a9f08ebbfa" },
- PublicKeyWithPoP { bytes: x"b698c932cf7097d99c17bd6e9c9dc4eeba84278c621700a8f80ec726b1daa11e3ab55fc045b4dbadefbeef05c4182494" },
- PublicKeyWithPoP { bytes: x"934706a8b876d47a996d427e1526ce52c952d5ec0858d49cd262efb785b62b1972d06270b0a7adda1addc98433ad1843" },
- PublicKeyWithPoP { bytes: x"a4cd352daad3a0651c1998dfbaa7a748e08d248a54347544bfedd51a197e016bb6008e9b8e45a744e1a030cc3b27d2da" },
- ];
-
- // agg_pks[i] = \sum_{j <= i} pk[j]
- let agg_pks = vector[
- AggrPublicKeysWithPoP { bytes: x"92e201a806af246f805f460fbdc6fc90dd16a18d6accc236e85d3578671d6f6690dde22134d19596c58ce9d63252410a" },
- AggrPublicKeysWithPoP { bytes: x"b79ad47abb441d7eda9b220a626df2e4e4910738c5f777947f0213398ecafae044ec0c20d552d1348347e9abfcf3eca1" },
- AggrPublicKeysWithPoP { bytes: x"b5f5eb6153ab5388a1a76343d714e4a2dcf224c5d0722d1e8e90c6bcead05c573fffe986460bd4000645a655bf52bc60" },
- AggrPublicKeysWithPoP { bytes: x"b922006ec14c183572a8864c31dc6632dccffa9f9c86411796f8b1b5a93a2457762c8e2f5ef0a2303506c4bca9a4e0bf" },
- AggrPublicKeysWithPoP { bytes: x"b53df1cfee2168f59e5792e710bf22928dc0553e6531dae5c7656c0a66fc12cb82fbb04863938c953dc901a5a79cc0f3" },
- ];
-
- // multisigs[i] is a signature on "Hello, Aptoverse!" under agg_pks[i]
- let multisigs = vector[
- AggrOrMultiSignature { bytes: x"ade45c67bff09ae57e0575feb0be870f2d351ce078e8033d847615099366da1299c69497027b77badb226ff1708543cd062597030c3f1553e0aef6c17e7af5dd0de63c1e4f1f9da68c966ea6c1dcade2cdc646bd5e8bcd4773931021ec5be3fd" },
- AggrOrMultiSignature { bytes: x"964af3d83436f6a9a382f34590c0c14e4454dc1de536af205319ce1ed417b87a2374863d5df7b7d5ed900cf91dffa7a105d3f308831d698c0d74fb2259d4813434fb86425db0ded664ae8f85d02ec1d31734910317d4155cbf69017735900d4d" },
- AggrOrMultiSignature { bytes: x"b523a31813e771e55aa0fc99a48db716ecc1085f9899ccadb64e759ecb481a2fb1cdcc0b266f036695f941361de773081729311f6a1bca9d47393f5359c8c87dc34a91f5dae335590aacbff974076ad1f910dd81750553a72ccbcad3c8cc0f07" },
- AggrOrMultiSignature { bytes: x"a945f61699df58617d37530a85e67bd1181349678b89293951ed29d1fb7588b5c12ebb7917dfc9d674f3f4fde4d062740b85a5f4927f5a4f0091e46e1ac6e41bbd650a74dd49e91445339d741e3b10bdeb9bc8bba46833e0011ff91fa5c77bd2" },
- AggrOrMultiSignature { bytes: x"b627b2cfd8ae59dcf5e58cc6c230ae369985fd096e1bc3be38da5deafcbed7d939f07cccc75383539940c56c6b6453db193f563f5b6e4fe54915afd9e1baea40a297fa7eda74abbdcd4cc5c667d6db3b9bd265782f7693798894400f2beb4637" },
- ];
-
- let i = 0;
- let accum_pk = std::vector::empty();
- while (i < std::vector::length(&pks)) {
- std::vector::push_back(&mut accum_pk, *std::vector::borrow(&pks, i));
-
- let apk = aggregate_pubkeys(accum_pk);
-
- assert!(apk == *std::vector::borrow(&agg_pks, i), 1);
-
- assert!(verify_multisignature(std::vector::borrow(&multisigs, i), &apk, b"Hello, Aptoverse!"), 1);
-
- i = i + 1;
- };
- }
-
- #[test]
- fun test_verify_multisignature_randomized() {
- let signer_count = 1;
- let max_signer_count = 5;
- let msg = b"hello world";
- while (signer_count <= max_signer_count) {
- // Generate key pairs.
- let signing_keys = vector[];
- let public_keys = vector[];
- let i = 0;
- while (i < signer_count) {
- let (sk, pk) = generate_keys();
- std::vector::push_back(&mut signing_keys, sk);
- std::vector::push_back(&mut public_keys, pk);
- i = i + 1;
- };
-
- // Generate multi-signature.
- let aggr_pk = aggregate_pubkeys(public_keys);
- let multisig = multi_sign_arbitrary_bytes(&signing_keys, msg);
-
- // Test signature verification.
- assert!(verify_multisignature(&multisig, &aggr_pk, msg), 1);
- assert!(!verify_multisignature(&maul_aggr_or_multi_signature(&multisig), &aggr_pk, msg), 1);
- assert!(!verify_multisignature(&multisig, &maul_aggregated_public_key(&aggr_pk), msg), 1);
- assert!(!verify_multisignature(&multisig, &aggr_pk, maul_bytes(&msg)), 1);
-
- // Also test signature aggregation.
- let signatures = vector[];
- let i = 0;
- while (i < signer_count) {
- let sk = std::vector::borrow(&signing_keys, i);
- let sig = sign_arbitrary_bytes(sk, msg);
- std::vector::push_back(&mut signatures, sig);
- i = i + 1;
- };
- let aggregated_signature = option::extract(&mut aggregate_signatures(signatures));
- assert!(aggr_or_multi_signature_subgroup_check(&aggregated_signature), 1);
- assert!(aggr_or_multi_signature_to_bytes(&aggregated_signature) == aggr_or_multi_signature_to_bytes(&multisig), 1);
-
- signer_count = signer_count + 1;
- }
- }
-
- #[test]
- fun test_verify_aggsig() {
- assert!(aggr_or_multi_signature_to_bytes(&aggr_or_multi_signature_from_bytes(RANDOM_SIGNATURE)) == RANDOM_SIGNATURE, 1);
-
- // First, make sure verification returns None when no inputs are given or |pks| != |msgs|
- assert!(verify_aggregate_signature(&get_random_aggsig(), vector[], vector[]) == false, 1);
-
- assert!(verify_aggregate_signature(
- &get_random_aggsig(),
- vector[ get_random_pk_with_pop() ],
- vector[]) == false, 1);
-
- assert!(verify_aggregate_signature(
- &get_random_aggsig(),
- vector[],
- vector[ x"ab" ]) == false, 1);
-
- assert!(verify_aggregate_signature(
- &get_random_aggsig(),
- vector[ get_random_pk_with_pop() ],
- vector[
- x"cd", x"ef"
- ]) == false, 1);
-
- assert!(verify_aggregate_signature(
- &get_random_aggsig(),
- vector[
- get_random_pk_with_pop(),
- get_random_pk_with_pop(),
- get_random_pk_with_pop(),
- ],
- vector[
- x"cd", x"ef"
- ]) == false, 1);
-
- // Second, try some test-cases generated by running the following command in `crates/aptos-crypto`:
- // $ cargo test -- bls12381_sample_aggregate_pk_and_aggsig --nocapture --ignored
-
- // The signed messages are "Hello, Aptos !", where \in {1, ..., 5}
- let msgs = vector[
- x"48656c6c6f2c204170746f73203121",
- x"48656c6c6f2c204170746f73203221",
- x"48656c6c6f2c204170746f73203321",
- x"48656c6c6f2c204170746f73203421",
- x"48656c6c6f2c204170746f73203521",
- ];
-
- // Public key of signer i
- let pks = vector[
- PublicKeyWithPoP { bytes: x"b93d6aabb2b83e52f4b8bda43c24ea920bbced87a03ffc80f8f70c814a8b3f5d69fbb4e579ca76ee008d61365747dbc6" },
- PublicKeyWithPoP { bytes: x"b45648ceae3a983bcb816a96db599b5aef3b688c5753fa20ce36ac7a4f2c9ed792ab20af6604e85e42dab746398bb82c" },
- PublicKeyWithPoP { bytes: x"b3e4921277221e01ed71284be5e3045292b26c7f465a6fcdba53ee47edd39ec5160da3b229a73c75671024dcb36de091" },
- PublicKeyWithPoP { bytes: x"8463b8671c9775a7dbd98bf76d3deba90b5a90535fc87dc8c13506bb5c7bbd99be4d257e60c548140e1e30b107ff5822" },
- PublicKeyWithPoP { bytes: x"a79e3d0e9d04587a3b27d05efe5717da05fd93485dc47978c866dc70a01695c2efd247d1dd843a011a4b6b24079d7384" },
- ];
-
- // aggsigs[i] = \sum_{j <= i} sigs[j], where sigs[j] is a signature on msgs[j] under pks[j]
- let aggsigs = vector[
- AggrOrMultiSignature { bytes: x"a2bc8bdebe6215ba74b5b53c5ed2aa0c68221a4adf868989ccdcfb62bb0eecc6537def9ee686a7960169c5917d25e5220177ed1c5e95ecfd68c09694062e76efcb00759beac874e4f9a715fd144210883bf9bb272f156b0a1fa15d0e9460f01f" },
- AggrOrMultiSignature { bytes: x"a523aa3c3f1f1074d968ffecf017c7b93ae5243006bf0abd2e45c036ddbec99302984b650ebe5ba306cda4071d281ba50a99ef0e66c3957fab94163296f9d673fc58a36de4276f82bfb1d9180b591df93b5c2804d40dd68cf0f72cd92f86442e" },
- AggrOrMultiSignature { bytes: x"abed10f464de74769121fc09715e59a3ac96a5054a43a9d43cc890a2d4d332614c74c7fb4cceef6d25f85c65dee337330f062f89f23fec9ecf7ce3193fbba2c886630d753be6a4513a4634428904b767af2f230c5cadbcb53a451dd9c7d977f6" },
- AggrOrMultiSignature { bytes: x"8362871631ba822742a31209fa4abce6dc94b741ac4725995459da2951324b51efbbf6bc3ab4681e547ebfbadd80e0360dc078c04188198f0acea26c12645ace9107a4a23cf8db46abc7a402637f16a0477c72569fc9966fe804ef4dc0e5e758" },
- AggrOrMultiSignature { bytes: x"a44d967935fbe63a763ce2dd2b16981f967ecd31e20d3266eef5517530cdc233c8a18273b6d9fd7f61dd39178826e3f115df4e7b304f2de17373a95ea0c9a14293dcfd6f0ef416e06fa23f6a3c850d638e4d8f97ab4562ef55d49a96a50baa13" },
- ];
-
- let i = 0;
- let msg_subset = std::vector::empty>();
- let pk_subset = std::vector::empty();
- while (i < std::vector::length(&pks)) {
- let aggsig = *std::vector::borrow(&aggsigs, i);
-
- std::vector::push_back(&mut pk_subset, *std::vector::borrow(&pks, i));
- std::vector::push_back(&mut msg_subset, *std::vector::borrow(&msgs, i));
-
- assert!(verify_aggregate_signature(&aggsig, pk_subset, msg_subset), 1);
-
- i = i + 1;
- };
- }
-
- #[test]
- fun test_verify_aggregated_signature_randomized() {
- let signer_count = 1;
- let max_signer_count = 5;
- while (signer_count <= max_signer_count) {
- // Generate key pairs and messages.
- let signing_keys = vector[];
- let public_keys = vector[];
- let messages: vector> = vector[];
- let i = 0;
- while (i < signer_count) {
- let (sk, pk) = generate_keys();
- std::vector::push_back(&mut signing_keys, sk);
- std::vector::push_back(&mut public_keys, pk);
- let msg: vector = vector[104, 101, 108, 108, 111, 32, 97, 112, 116, 111, 115, 32, 117, 115, 101, 114, 32, 48+(i as u8)]; //"hello aptos user {i}"
- std::vector::push_back(&mut messages, msg);
- i = i + 1;
- };
-
- // Maul messages and public keys.
- let mauled_public_keys = vector[maul_public_key_with_pop(std::vector::borrow(&public_keys, 0))];
- let mauled_messages = vector[maul_bytes(std::vector::borrow(&messages, 0))];
- let i = 1;
- while (i < signer_count) {
- let pk = std::vector::borrow(&public_keys, i);
- let msg = std::vector::borrow(&messages, i);
- std::vector::push_back(&mut mauled_public_keys, *pk);
- std::vector::push_back(&mut mauled_messages, *msg);
- i = i + 1;
- };
-
- // Generate aggregated signature.
- let aggrsig = aggr_sign_arbitrary_bytes(&signing_keys, &messages);
-
- // Test signature verification.
- assert!(verify_aggregate_signature(&aggrsig, public_keys, messages), 1);
- assert!(!verify_aggregate_signature(&maul_aggr_or_multi_signature(&aggrsig), public_keys, messages), 1);
- assert!(!verify_aggregate_signature(&aggrsig, mauled_public_keys, messages), 1);
- assert!(!verify_aggregate_signature(&aggrsig, public_keys, mauled_messages), 1);
-
- // Also test signature aggregation.
- let signatures = vector[];
- let i = 0;
- while (i < signer_count) {
- let sk = std::vector::borrow(&signing_keys, i);
- let msg = std::vector::borrow(&messages, i);
- let sig = sign_arbitrary_bytes(sk, *msg);
- std::vector::push_back(&mut signatures, sig);
- i = i + 1;
- };
- let aggrsig_another = option::extract(&mut aggregate_signatures(signatures));
- assert!(aggr_or_multi_signature_to_bytes(&aggrsig_another) == aggr_or_multi_signature_to_bytes(&aggrsig), 1);
-
- signer_count = signer_count + 1;
- }
- }
-
- #[test]
- /// Tests verification of a random BLS signature created using sk = x""
- fun test_verify_normal_and_verify_sigshare() {
- // Test case generated by running `cargo test -- bls12381_sample_signature --nocapture --include-ignored` in
- // `crates/aptos-crypto`
- // =============================================================================================================
- // SK: 077c8a56f26259215a4a245373ab6ddf328ac6e00e5ea38d8700efa361bdc58d
-
- let message = b"Hello Aptos!";
-
- // First, test signatures that verify
- let ok = verify_normal_signature(
- &signature_from_bytes(x"b01ce4632e94d8c611736e96aa2ad8e0528a02f927a81a92db8047b002a8c71dc2d6bfb94729d0973790c10b6ece446817e4b7543afd7ca9a17c75de301ae835d66231c26a003f11ae26802b98d90869a9e73788c38739f7ac9d52659e1f7cf7"),
- &option::extract(&mut public_key_from_bytes(x"94209a296b739577cb076d3bfb1ca8ee936f29b69b7dae436118c4dd1cc26fd43dcd16249476a006b8b949bf022a7858")),
- message,
- );
- assert!(ok == true, 1);
-
- let pk = option::extract(&mut public_key_from_bytes(x"94209a296b739577cb076d3bfb1ca8ee936f29b69b7dae436118c4dd1cc26fd43dcd16249476a006b8b949bf022a7858"));
- let pk_with_pop = PublicKeyWithPoP { bytes: pk.bytes };
-
- let ok = verify_signature_share(
- &signature_from_bytes(x"b01ce4632e94d8c611736e96aa2ad8e0528a02f927a81a92db8047b002a8c71dc2d6bfb94729d0973790c10b6ece446817e4b7543afd7ca9a17c75de301ae835d66231c26a003f11ae26802b98d90869a9e73788c38739f7ac9d52659e1f7cf7"),
- &pk_with_pop,
- message,
- );
- assert!(ok == true, 1);
-
- // Second, test signatures that do NOT verify
- let sigs = vector[
- Signature { bytes: x"a01ce4632e94d8c611736e96aa2ad8e0528a02f927a81a92db8047b002a8c71dc2d6bfb94729d0973790c10b6ece446817e4b7543afd7ca9a17c75de301ae835d66231c26a003f11ae26802b98d90869a9e73788c38739f7ac9d52659e1f7cf7" },
- Signature { bytes: x"b01ce4632e94d8c611736e96aa2ad8e0528a02f927a81a92db8047b002a8c71dc2d6bfb94729d0973790c10b6ece446817e4b7543afd7ca9a17c75de301ae835d66231c26a003f11ae26802b98d90869a9e73788c38739f7ac9d52659e1f7cf7" },
- Signature { bytes: x"b01ce4632e94d8c611736e96aa2ad8e0528a02f927a81a92db8047b002a8c71dc2d6bfb94729d0973790c10b6ece446817e4b7543afd7ca9a17c75de301ae835d66231c26a003f11ae26802b98d90869a9e73788c38739f7ac9d52659e1f7cf7" },
- ];
- let pks = vector[
- x"94209a296b739577cb076d3bfb1ca8ee936f29b69b7dae436118c4dd1cc26fd43dcd16249476a006b8b949bf022a7858",
- x"ae4851bb9e7782027437ed0e2c026dd63b77a972ddf4bd9f72bcc218e327986568317e3aa9f679c697a2cb7cebf992f3",
- x"82ed7bb5528303a2e306775040a7309e0bd597b70d9949d8c6198a01a7be0b00079320ebfeaf7bbd5bfe86809940d252",
- ];
- let messages = vector[
- b"Hello Aptos!",
- b"Hello Aptos!",
- b"Bello Aptos!",
- ];
-
- let i = 0;
- while (i < std::vector::length(&pks)) {
- let sig = std::vector::borrow(&sigs, i);
- let pk = *std::vector::borrow(&pks, i);
- let msg = *std::vector::borrow(&messages, i);
-
- let pk = option::extract(&mut public_key_from_bytes(pk));
-
- let notok = verify_normal_signature(
- sig,
- &pk,
- msg,
- );
- assert!(notok == false, 1);
-
- let notok = verify_signature_share(
- sig,
- &PublicKeyWithPoP { bytes: pk.bytes },
- msg,
- );
- assert!(notok == false, 1);
-
- i = i + 1;
- }
- }
-
- #[test]
- fun test_verify_normal_signature_or_signature_share_randomized() {
- let (sk, pkpop) = generate_keys();
- let pk = public_key_with_pop_to_normal(&pkpop);
-
- let msg = b"hello world";
- let sig = sign_arbitrary_bytes(&sk, msg);
- assert!(verify_normal_signature(&sig, &pk, msg), 1);
- assert!(!verify_normal_signature(&maul_signature(&sig), &pk, msg), 1);
- assert!(!verify_normal_signature(&sig, &maul_public_key(&pk), msg), 1);
- assert!(!verify_normal_signature(&sig, &pk, maul_bytes(&msg)), 1);
-
- assert!(verify_signature_share(&sig, &pkpop, msg), 1);
- assert!(!verify_signature_share(&maul_signature(&sig), &pkpop, msg), 1);
- assert!(!verify_signature_share(&sig, &maul_public_key_with_pop(&pkpop), msg), 1);
- assert!(!verify_signature_share(&sig, &pkpop, maul_bytes(&msg)), 1);
- }
-
- #[test]
- /// Tests verification of random BLS proofs-of-possession (PoPs)
- fun test_verify_pop() {
- // Test case generated by running `cargo test -- sample_pop --nocapture --include-ignored` in `crates/aptos-crypto`
- // =============================================================================================================
-
- let pks = vector[
- x"808864c91ae7a9998b3f5ee71f447840864e56d79838e4785ff5126c51480198df3d972e1e0348c6da80d396983e42d7",
- x"8843843c76d167c02842a214c21277bad0bfd83da467cb5cf2d3ee67b2dcc7221b9fafa6d430400164012580e0c34d27",
- x"a23b524d4308d46e43ee8cbbf57f3e1c20c47061ad9c3f915212334ea6532451dd5c01d3d3ada6bea10fe180b2c3b450",
- x"a2aaa3eae1df3fc36365491afa1da5181acbb03801afd1430f04bb3b3eb18036f8b756b3508e4caee04beff50d455d1c",
- x"84985b7e983dbdaddfca1f0b7dad9660bb39fff660e329acec15f69ac48c75dfa5d2df9f0dc320e4e7b7658166e0ac1c",
- ];
-
- let pops = vector[
- proof_of_possession_from_bytes(x"ab42afff92510034bf1232a37a0d31bc8abfc17e7ead9170d2d100f6cf6c75ccdcfedbd31699a112b4464a06fd636f3f190595863677d660b4c5d922268ace421f9e86e3a054946ee34ce29e1f88c1a10f27587cf5ec528d65ba7c0dc4863364"),
- proof_of_possession_from_bytes(x"a6da5f2bc17df70ce664cff3e3a3e09d17162e47e652032b9fedc0c772fd5a533583242cba12095602e422e579c5284b1735009332dbdd23430bbcf61cc506ae37e41ff9a1fc78f0bc0d99b6bc7bf74c8f567dfb59079a035842bdc5fa3a0464"),
- proof_of_possession_from_bytes(x"b8eef236595e2eab34d3c1abdab65971f5cfa1988c731ef62bd63c9a9ad3dfc9259f4f183bfffbc8375a38ba62e1c41a11173209705996ce889859bcbb3ddd7faa3c4ea3d8778f30a9ff814fdcfea1fb163d745c54dfb4dcc5a8cee092ee0070"),
- proof_of_possession_from_bytes(x"a03a12fab68ad59d85c15dd1528560eff2c89250070ad0654ba260fda4334da179811d2ecdaca57693f80e9ce977d62011e3b1ee7bb4f7e0eb9b349468dd758f10fc35d54e0d0b8536ca713a77a301944392a5c192b6adf2a79ae2b38912dc98"),
- proof_of_possession_from_bytes(x"8899b294f3c066e6dfb59bc0843265a1ccd6afc8f0f38a074d45ded8799c39d25ee0376cd6d6153b0d4d2ff8655e578b140254f1287b9e9df4e2aecc5b049d8556a4ab07f574df68e46348fd78e5298b7913377cf5bb3cf4796bfc755902bfdd"),
- ];
-
- assert!(std::vector::length(&pks) == std::vector::length(&pops), 1);
-
- let i = 0;
- while (i < std::vector::length(&pks)) {
- let opt_pk = public_key_from_bytes_with_pop(*std::vector::borrow(&pks, i), std::vector::borrow(&pops, i));
- assert!(option::is_some(&opt_pk), 1);
-
- i = i + 1;
- };
-
- // assert first PK's PoP does not verify against modifed PK' = 0xa0 | PK[1:]
- let opt_pk = public_key_from_bytes_with_pop(
- x"a08864c91ae7a9998b3f5ee71f447840864e56d79838e4785ff5126c51480198df3d972e1e0348c6da80d396983e42d7",
- &proof_of_possession_from_bytes(x"ab42afff92510034bf1232a37a0d31bc8abfc17e7ead9170d2d100f6cf6c75ccdcfedbd31699a112b4464a06fd636f3f190595863677d660b4c5d922268ace421f9e86e3a054946ee34ce29e1f88c1a10f27587cf5ec528d65ba7c0dc4863364"));
- assert!(option::is_none(&opt_pk), 1);
-
- // assert first PK's PoP does not verify if modifed as pop' = 0xb0 | pop[1:]
- let opt_pk = public_key_from_bytes_with_pop(
- x"808864c91ae7a9998b3f5ee71f447840864e56d79838e4785ff5126c51480198df3d972e1e0348c6da80d396983e42d7",
- &proof_of_possession_from_bytes(x"bb42afff92510034bf1232a37a0d31bc8abfc17e7ead9170d2d100f6cf6c75ccdcfedbd31699a112b4464a06fd636f3f190595863677d660b4c5d922268ace421f9e86e3a054946ee34ce29e1f88c1a10f27587cf5ec528d65ba7c0dc4863364"));
- assert!(option::is_none(&opt_pk), 1);
- }
-
- #[test]
- fun test_verify_pop_randomized() {
- let (sk, pk) = generate_keys();
- let pk_bytes = public_key_with_pop_to_bytes(&pk);
- let pop = generate_proof_of_possession(&sk);
- assert!(option::is_some(&public_key_from_bytes_with_pop(pk_bytes, &pop)), 1);
- assert!(option::is_none(&public_key_from_bytes_with_pop(pk_bytes, &maul_proof_of_possession(&pop))), 1);
- assert!(option::is_none(&public_key_from_bytes_with_pop(maul_bytes(&pk_bytes), &pop)), 1);
- }
-}
diff --git a/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381.spec.move b/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381.spec.move
deleted file mode 100644
index fcac18cf7ac7a3..00000000000000
--- a/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381.spec.move
+++ /dev/null
@@ -1,164 +0,0 @@
-spec aptos_std::bls12381 {
-
- spec public_key_from_bytes {
- aborts_if false;
- ensures spec_validate_pubkey_internal(bytes) ==> (std::option::spec_is_some(result) && std::option::spec_borrow(result).bytes == bytes);
- ensures !spec_validate_pubkey_internal(bytes) ==> std::option::spec_is_none(result);
- }
-
- spec public_key_from_bytes_with_pop {
- pragma opaque;
- aborts_if false;
- ensures spec_verify_proof_of_possession_internal(pk_bytes, pop.bytes) ==> (std::option::spec_is_some(result) && std::option::spec_borrow(result).bytes == pk_bytes);
- ensures !spec_verify_proof_of_possession_internal(pk_bytes, pop.bytes) ==> std::option::spec_is_none(result);
- ensures [abstract] result == spec_public_key_from_bytes_with_pop(pk_bytes, pop);
- }
-
- spec aggregate_pubkeys {
- let bytes = spec_aggregate_pubkeys_internal_1(public_keys);
- let success = spec_aggregate_pubkeys_internal_2(public_keys);
- aborts_if !success;
- ensures result.bytes == bytes;
- }
-
- spec aggregate_pubkeys_internal {
- pragma opaque;
- aborts_if [abstract] false; //TODO: check the aborts_if condition in the native implementation
- ensures result_1 == spec_aggregate_pubkeys_internal_1(public_keys);
- ensures result_2 == spec_aggregate_pubkeys_internal_2(public_keys);
- }
-
- spec aggregate_signatures {
- aborts_if false;
- let bytes = spec_aggregate_signatures_internal_1(signatures);
- let success = spec_aggregate_signatures_internal_2(signatures);
- ensures success ==> (std::option::spec_is_some(result) && std::option::spec_borrow(result).bytes == bytes);
- ensures !success ==> std::option::spec_is_none(result);
- }
-
- spec aggregate_signatures_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result_1 == spec_aggregate_signatures_internal_1(signatures);
- ensures result_2 == spec_aggregate_signatures_internal_2(signatures);
- }
-
- spec aggr_or_multi_signature_from_bytes {
- aborts_if len(bytes) != SIGNATURE_SIZE;
- ensures result.bytes == bytes;
- }
-
- spec validate_pubkey_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result == spec_validate_pubkey_internal(public_key);
- }
-
- spec aggr_or_multi_signature_subgroup_check {
- aborts_if false;
- ensures result == spec_signature_subgroup_check_internal(signature.bytes);
- }
-
- spec signature_subgroup_check_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result == spec_signature_subgroup_check_internal(signature);
- }
-
- spec verify_aggregate_signature {
- aborts_if false;
- ensures result == spec_verify_aggregate_signature_internal(aggr_sig.bytes, public_keys, messages);
- }
-
- spec verify_aggregate_signature_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result == spec_verify_aggregate_signature_internal(aggsig, public_keys, messages);
- }
-
- spec verify_multisignature {
- aborts_if false;
- ensures result == spec_verify_multisignature_internal(multisig.bytes, aggr_public_key.bytes, message);
- }
-
- spec verify_multisignature_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result == spec_verify_multisignature_internal(multisignature, agg_public_key, message);
- }
-
- spec verify_normal_signature {
- aborts_if false;
- ensures result == spec_verify_normal_signature_internal(signature.bytes, public_key.bytes, message);
- }
-
- spec verify_normal_signature_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result == spec_verify_normal_signature_internal(signature, public_key, message);
- }
-
- spec verify_proof_of_possession_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result == spec_verify_proof_of_possession_internal(public_key, proof_of_possesion);
- }
-
- spec verify_signature_share {
- aborts_if false;
- ensures result == spec_verify_signature_share_internal(signature_share.bytes, public_key.bytes, message);
- }
-
- spec verify_signature_share_internal {
- pragma opaque;
- aborts_if [abstract] false;
- ensures result == spec_verify_signature_share_internal(signature_share, public_key, message);
- }
-
- /// # Helper functions
-
- spec fun spec_aggregate_pubkeys_internal_1(public_keys: vector): vector;
-
- spec fun spec_public_key_from_bytes_with_pop(pk_bytes: vector, pop: ProofOfPossession): Option;
-
- spec fun spec_aggregate_pubkeys_internal_2(public_keys: vector): bool;
-
- spec fun spec_aggregate_signatures_internal_1(signatures: vector): vector;
-
- spec fun spec_aggregate_signatures_internal_2(signatures: vector): bool;
-
- spec fun spec_validate_pubkey_internal(public_key: vector): bool;
-
- spec fun spec_signature_subgroup_check_internal(signature: vector): bool;
-
- spec fun spec_verify_aggregate_signature_internal(
- aggsig: vector,
- public_keys: vector,
- messages: vector>,
- ): bool;
-
- spec fun spec_verify_multisignature_internal(
- multisignature: vector,
- agg_public_key: vector,
- message: vector
- ): bool;
-
- spec fun spec_verify_normal_signature_internal(
- signature: vector,
- public_key: vector,
- message: vector
- ): bool;
-
- spec fun spec_verify_proof_of_possession_internal(
- public_key: vector,
- proof_of_possesion: vector
- ): bool;
-
- spec fun spec_verify_signature_share_internal(
- signature_share: vector,
- public_key: vector,
- message: vector
- ): bool;
-
-
-}
diff --git a/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381_algebra.move b/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381_algebra.move
deleted file mode 100644
index 5fb99beb93c1bd..00000000000000
--- a/aptos-move/framework/aptos-stdlib/sources/cryptography/bls12381_algebra.move
+++ /dev/null
@@ -1,802 +0,0 @@
-/// This module defines marker types, constants and test cases for working with BLS12-381 curves
-/// using the generic API defined in `algebra.move`.
-/// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-pairing-friendly-curves-11#name-bls-curves-for-the-128-bit-
-/// for the full specification of BLS12-381 curves.
-///
-/// Currently-supported BLS12-381 structures include `Fq12`, `Fr`, `G1`, `G2` and `Gt`,
-/// along with their widely-used serialization formats,
-/// the pairing between `G1`, `G2` and `Gt`,
-/// and the hash-to-curve operations for `G1` and `G2` defined in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16.
-///
-/// Other unimplemented BLS12-381 structures and serialization formats are also listed here,
-/// as they help define some of the currently supported structures.
-/// Their implementation may also be added in the future.
-///
-/// `Fq`: the finite field $F_q$ used in BLS12-381 curves with a prime order $q$ equal to
-/// 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab.
-///
-/// `FormatFqLsb`: a serialization format for `Fq` elements,
-/// where an element is represented by a byte array `b[]` of size 48 with the least significant byte (LSB) coming first.
-///
-/// `FormatFqMsb`: a serialization format for `Fq` elements,
-/// where an element is represented by a byte array `b[]` of size 48 with the most significant byte (MSB) coming first.
-///
-/// `Fq2`: the finite field $F_{q^2}$ used in BLS12-381 curves,
-/// which is an extension field of `Fq`, constructed as $F_{q^2}=F_q[u]/(u^2+1)$.
-///
-/// `FormatFq2LscLsb`: a serialization format for `Fq2` elements,
-/// where an element in the form $(c_0+c_1\cdot u)$ is represented by a byte array `b[]` of size 96,
-/// which is a concatenation of its coefficients serialized, with the least significant coefficient (LSC) coming first:
-/// - `b[0..48]` is $c_0$ serialized using `FormatFqLsb`.
-/// - `b[48..96]` is $c_1$ serialized using `FormatFqLsb`.
-///
-/// `FormatFq2MscMsb`: a serialization format for `Fq2` elements,
-/// where an element in the form $(c_0+c_1\cdot u)$ is represented by a byte array `b[]` of size 96,
-/// which is a concatenation of its coefficients serialized, with the most significant coefficient (MSC) coming first:
-/// - `b[0..48]` is $c_1$ serialized using `FormatFqLsb`.
-/// - `b[48..96]` is $c_0$ serialized using `FormatFqLsb`.
-///
-/// `Fq6`: the finite field $F_{q^6}$ used in BLS12-381 curves,
-/// which is an extension field of `Fq2`, constructed as $F_{q^6}=F_{q^2}[v]/(v^3-u-1)$.
-///
-/// `FormatFq6LscLsb`: a serialization scheme for `Fq6` elements,
-/// where an element in the form $(c_0+c_1\cdot v+c_2\cdot v^2)$ is represented by a byte array `b[]` of size 288,
-/// which is a concatenation of its coefficients serialized, with the least significant coefficient (LSC) coming first:
-/// - `b[0..96]` is $c_0$ serialized using `FormatFq2LscLsb`.
-/// - `b[96..192]` is $c_1$ serialized using `FormatFq2LscLsb`.
-/// - `b[192..288]` is $c_2$ serialized using `FormatFq2LscLsb`.
-///
-/// `G1Full`: a group constructed by the points on the BLS12-381 curve $E(F_q): y^2=x^3+4$ and the point at infinity,
-/// under the elliptic curve point addition.
-/// It contains the prime-order subgroup $G_1$ used in pairing.
-///
-/// `G2Full`: a group constructed by the points on a curve $E'(F_{q^2}): y^2=x^3+4(u+1)$ and the point at infinity,
-/// under the elliptic curve point addition.
-/// It contains the prime-order subgroup $G_2$ used in pairing.
-module aptos_std::bls12381_algebra {
- //
- // Marker types + serialization formats begin.
- //
-
- /// The finite field $F_{q^12}$ used in BLS12-381 curves,
- /// which is an extension field of `Fq6` (defined in the module documentation), constructed as $F_{q^12}=F_{q^6}[w]/(w^2-v)$.
- struct Fq12 {}
-
- /// A serialization scheme for `Fq12` elements,
- /// where an element $(c_0+c_1\cdot w)$ is represented by a byte array `b[]` of size 576,
- /// which is a concatenation of its coefficients serialized, with the least significant coefficient (LSC) coming first.
- /// - `b[0..288]` is $c_0$ serialized using `FormatFq6LscLsb` (defined in the module documentation).
- /// - `b[288..576]` is $c_1$ serialized using `FormatFq6LscLsb`.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0.
- struct FormatFq12LscLsb {}
-
- /// The group $G_1$ in BLS12-381-based pairing $G_1 \times G_2 \rightarrow G_t$.
- /// It is a subgroup of `G1Full` (defined in the module documentation) with a prime order $r$
- /// equal to 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001.
- /// (so `Fr` is the associated scalar field).
- struct G1 {}
-
- /// A serialization scheme for `G1` elements derived from
- /// https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-11.html#name-zcash-serialization-format-.
- ///
- /// Below is the serialization procedure that takes a `G1` element `p` and outputs a byte array of size 96.
- /// 1. Let `(x,y)` be the coordinates of `p` if `p` is on the curve, or `(0,0)` otherwise.
- /// 1. Serialize `x` and `y` into `b_x[]` and `b_y[]` respectively using `FormatFqMsb` (defined in the module documentation).
- /// 1. Concatenate `b_x[]` and `b_y[]` into `b[]`.
- /// 1. If `p` is the point at infinity, set the infinity bit: `b[0]: = b[0] | 0x40`.
- /// 1. Return `b[]`.
- ///
- /// Below is the deserialization procedure that takes a byte array `b[]` and outputs either a `G1` element or none.
- /// 1. If the size of `b[]` is not 96, return none.
- /// 1. Compute the compression flag as `b[0] & 0x80 != 0`.
- /// 1. If the compression flag is true, return none.
- /// 1. Compute the infinity flag as `b[0] & 0x40 != 0`.
- /// 1. If the infinity flag is set, return the point at infinity.
- /// 1. Deserialize `[b[0] & 0x1f, b[1], ..., b[47]]` to `x` using `FormatFqMsb`. If `x` is none, return none.
- /// 1. Deserialize `[b[48], ..., b[95]]` to `y` using `FormatFqMsb`. If `y` is none, return none.
- /// 1. Check if `(x,y)` is on curve `E`. If not, return none.
- /// 1. Check if `(x,y)` is in the subgroup of order `r`. If not, return none.
- /// 1. Return `(x,y)`.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0.
- struct FormatG1Uncompr {}
-
- /// A serialization scheme for `G1` elements derived from
- /// https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-11.html#name-zcash-serialization-format-.
- ///
- /// Below is the serialization procedure that takes a `G1` element `p` and outputs a byte array of size 48.
- /// 1. Let `(x,y)` be the coordinates of `p` if `p` is on the curve, or `(0,0)` otherwise.
- /// 1. Serialize `x` into `b[]` using `FormatFqMsb` (defined in the module documentation).
- /// 1. Set the compression bit: `b[0] := b[0] | 0x80`.
- /// 1. If `p` is the point at infinity, set the infinity bit: `b[0]: = b[0] | 0x40`.
- /// 1. If `y > -y`, set the lexicographical flag: `b[0] := b[0] | 0x20`.
- /// 1. Return `b[]`.
- ///
- /// Below is the deserialization procedure that takes a byte array `b[]` and outputs either a `G1` element or none.
- /// 1. If the size of `b[]` is not 48, return none.
- /// 1. Compute the compression flag as `b[0] & 0x80 != 0`.
- /// 1. If the compression flag is false, return none.
- /// 1. Compute the infinity flag as `b[0] & 0x40 != 0`.
- /// 1. If the infinity flag is set, return the point at infinity.
- /// 1. Compute the lexicographical flag as `b[0] & 0x20 != 0`.
- /// 1. Deserialize `[b[0] & 0x1f, b[1], ..., b[47]]` to `x` using `FormatFqMsb`. If `x` is none, return none.
- /// 1. Solve the curve equation with `x` for `y`. If no such `y` exists, return none.
- /// 1. Let `y'` be `max(y,-y)` if the lexicographical flag is set, or `min(y,-y)` otherwise.
- /// 1. Check if `(x,y')` is in the subgroup of order `r`. If not, return none.
- /// 1. Return `(x,y')`.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0.
- struct FormatG1Compr {}
-
- /// The group $G_2$ in BLS12-381-based pairing $G_1 \times G_2 \rightarrow G_t$.
- /// It is a subgroup of `G2Full` (defined in the module documentation) with a prime order $r$ equal to
- /// 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001.
- /// (so `Fr` is the scalar field).
- struct G2 {}
-
- /// A serialization scheme for `G2` elements derived from
- /// https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-11.html#name-zcash-serialization-format-.
- ///
- /// Below is the serialization procedure that takes a `G2` element `p` and outputs a byte array of size 192.
- /// 1. Let `(x,y)` be the coordinates of `p` if `p` is on the curve, or `(0,0)` otherwise.
- /// 1. Serialize `x` and `y` into `b_x[]` and `b_y[]` respectively using `FormatFq2MscMsb` (defined in the module documentation).
- /// 1. Concatenate `b_x[]` and `b_y[]` into `b[]`.
- /// 1. If `p` is the point at infinity, set the infinity bit in `b[]`: `b[0]: = b[0] | 0x40`.
- /// 1. Return `b[]`.
- ///
- /// Below is the deserialization procedure that takes a byte array `b[]` and outputs either a `G2` element or none.
- /// 1. If the size of `b[]` is not 192, return none.
- /// 1. Compute the compression flag as `b[0] & 0x80 != 0`.
- /// 1. If the compression flag is true, return none.
- /// 1. Compute the infinity flag as `b[0] & 0x40 != 0`.
- /// 1. If the infinity flag is set, return the point at infinity.
- /// 1. Deserialize `[b[0] & 0x1f, ..., b[95]]` to `x` using `FormatFq2MscMsb`. If `x` is none, return none.
- /// 1. Deserialize `[b[96], ..., b[191]]` to `y` using `FormatFq2MscMsb`. If `y` is none, return none.
- /// 1. Check if `(x,y)` is on the curve `E'`. If not, return none.
- /// 1. Check if `(x,y)` is in the subgroup of order `r`. If not, return none.
- /// 1. Return `(x,y)`.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0.
- struct FormatG2Uncompr {}
-
- /// A serialization scheme for `G2` elements derived from
- /// https://www.ietf.org/archive/id/draft-irtf-cfrg-pairing-friendly-curves-11.html#name-zcash-serialization-format-.
- ///
- /// Below is the serialization procedure that takes a `G2` element `p` and outputs a byte array of size 96.
- /// 1. Let `(x,y)` be the coordinates of `p` if `p` is on the curve, or `(0,0)` otherwise.
- /// 1. Serialize `x` into `b[]` using `FormatFq2MscMsb` (defined in the module documentation).
- /// 1. Set the compression bit: `b[0] := b[0] | 0x80`.
- /// 1. If `p` is the point at infinity, set the infinity bit: `b[0]: = b[0] | 0x40`.
- /// 1. If `y > -y`, set the lexicographical flag: `b[0] := b[0] | 0x20`.
- /// 1. Return `b[]`.
- ///
- /// Below is the deserialization procedure that takes a byte array `b[]` and outputs either a `G2` element or none.
- /// 1. If the size of `b[]` is not 96, return none.
- /// 1. Compute the compression flag as `b[0] & 0x80 != 0`.
- /// 1. If the compression flag is false, return none.
- /// 1. Compute the infinity flag as `b[0] & 0x40 != 0`.
- /// 1. If the infinity flag is set, return the point at infinity.
- /// 1. Compute the lexicographical flag as `b[0] & 0x20 != 0`.
- /// 1. Deserialize `[b[0] & 0x1f, b[1], ..., b[95]]` to `x` using `FormatFq2MscMsb`. If `x` is none, return none.
- /// 1. Solve the curve equation with `x` for `y`. If no such `y` exists, return none.
- /// 1. Let `y'` be `max(y,-y)` if the lexicographical flag is set, or `min(y,-y)` otherwise.
- /// 1. Check if `(x,y')` is in the subgroup of order `r`. If not, return none.
- /// 1. Return `(x,y')`.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0.
- struct FormatG2Compr {}
-
- /// The group $G_t$ in BLS12-381-based pairing $G_1 \times G_2 \rightarrow G_t$.
- /// It is a multiplicative subgroup of `Fq12`,
- /// with a prime order $r$ equal to 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001.
- /// (so `Fr` is the scalar field).
- /// The identity of `Gt` is 1.
- struct Gt {}
-
- /// A serialization scheme for `Gt` elements.
- ///
- /// To serialize, it treats a `Gt` element `p` as an `Fq12` element and serialize it using `FormatFq12LscLsb`.
- ///
- /// To deserialize, it uses `FormatFq12LscLsb` to try deserializing to an `Fq12` element then test the membership in `Gt`.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0.
- struct FormatGt {}
-
- /// The finite field $F_r$ that can be used as the scalar fields
- /// associated with the groups $G_1$, $G_2$, $G_t$ in BLS12-381-based pairing.
- struct Fr {}
-
- /// A serialization format for `Fr` elements,
- /// where an element is represented by a byte array `b[]` of size 32 with the least significant byte (LSB) coming first.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0, blst-0.3.7.
- struct FormatFrLsb {}
-
- /// A serialization scheme for `Fr` elements,
- /// where an element is represented by a byte array `b[]` of size 32 with the most significant byte (MSB) coming first.
- ///
- /// NOTE: other implementation(s) using this format: ark-bls12-381-0.4.0, blst-0.3.7.
- struct FormatFrMsb {}
-
- //
- // (Marker types + serialization formats end here.)
- // Hash-to-structure suites begin.
- //
-
- /// The hash-to-curve suite `BLS12381G1_XMD:SHA-256_SSWU_RO_` that hashes a byte array into `G1` elements.
- ///
- /// Full specification is defined in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#name-bls12-381-g1.
- struct HashG1XmdSha256SswuRo {}
-
- /// The hash-to-curve suite `BLS12381G2_XMD:SHA-256_SSWU_RO_` that hashes a byte array into `G2` elements.
- ///
- /// Full specification is defined in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16#name-bls12-381-g2.
- struct HashG2XmdSha256SswuRo {}
-
- //
- // (Hash-to-structure suites end here.)
- // Tests begin.
- //
-
- #[test_only]
- const FQ12_VAL_0_SERIALIZED: vector = x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const FQ12_VAL_1_SERIALIZED: vector = x"010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const FQ12_VAL_7_SERIALIZED: vector = x"070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const FQ12_VAL_7_NEG_SERIALIZED: vector = x"a4aafffffffffeb9ffff53b1feffab1e24f6b0f6a0d23067bf1285f3844b7764d7ac4b43b6a71b4b9ae67f39ea11011a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const Q12_SERIALIZED: vector = x"1175f55da544c7625f8ccb1360e2b1d3ca40747811c8f5ed04440afe232b476c0215676aec05f2a44ac2da6b6d1b7cff075e7b2a587e0aab601a8d3db4f0d29906e5e4d0d78119f396d5a59f0f8d1ca8bca62540be6ab9c12d0ca00de1f311f106278d000e55a393c9766a74e0d08a298450f60d7e666575e3354bf14b8731f4e721c0c180a5ed55c2f8f51f815baecbf96b5fc717eb58ac161a27d1d5f2bdc1a079609b9d6449165b2466b32a01eac7992a1ea0cac2f223cde1d56f9bbccc67afe44621daf858df3fc0eb837818f3e42ab3e131ce4e492efa63c108e6ef91c29ed63b3045baebcb0ab8d203c7f558beaffccba31b12aca7f54b58d0c28340e4fdb3c7c94fe9c4fef9d640ff2fcff02f1748416cbed0981fbff49f0e39eaf8a30273e67ed851944d33d6a593ef5ddcd62da84568822a6045b633bf6a513b3cfe8f9de13e76f8dcbd915980dec205eab6a5c0c72dcebd9afff1d25509ddbf33f8e24131fbd74cda93336514340cf8036b66b09ed9e6a6ac37e22fb3ac407e321beae8cd9fe74c8aaeb4edaa9a7272848fc623f6fe835a2e647379f547fc5ec6371318a85bfa60009cb20ccbb8a467492988a87633c14c0324ba0d0c3e1798ed29c8494cea35023746da05e35d184b4a301d5b2238d665495c6318b5af8653758008952d06cb9e62487b196d64383c73c06d6e1cccdf9b3ce8f95679e7050d949004a55f4ccf95b2552880ae36d1f7e09504d2338316d87d14a064511a295d768113e301bdf9d4383a8be32192d3f2f3b2de14181c73839a7cb4af5301";
-
- #[test_only]
- fun rand_vector(num: u64): vector> {
- let elements = vector[];
- while (num > 0) {
- std::vector::push_back(&mut elements, rand_insecure());
- num = num - 1;
- };
- elements
- }
-
- #[test(fx = @std)]
- fun test_fq12(fx: signer) {
- enable_cryptography_algebra_natives(&fx);
-
- // Constants.
- assert!(Q12_SERIALIZED == order(), 1);
-
- // Serialization/deserialization.
- let val_0 = zero();
- let val_1 = one();
- assert!(FQ12_VAL_0_SERIALIZED == serialize(&val_0), 1);
- assert!(FQ12_VAL_1_SERIALIZED == serialize(&val_1), 1);
- let val_7 = from_u64(7);
- let val_7_another = std::option::extract(&mut deserialize(&FQ12_VAL_7_SERIALIZED));
- assert!(eq(&val_7, &val_7_another), 1);
- assert!(FQ12_VAL_7_SERIALIZED == serialize(&val_7), 1);
- assert!(std::option::is_none(&deserialize(&x"ffff")), 1);
-
- // Negation.
- let val_minus_7 = neg(&val_7);
- assert!(FQ12_VAL_7_NEG_SERIALIZED == serialize(&val_minus_7), 1);
-
- // Addition.
- let val_9 = from_u64(9);
- let val_2 = from_u64(2);
- assert!(eq(&val_2, &add(&val_minus_7, &val_9)), 1);
-
- // Subtraction.
- assert!(eq(&val_9, &sub(&val_2, &val_minus_7)), 1);
-
- // Multiplication.
- let val_63 = from_u64(63);
- assert!(eq(&val_63, &mul(&val_7, &val_9)), 1);
-
- // division.
- let val_0 = from_u64(0);
- assert!(eq(&val_7, &std::option::extract(&mut div(&val_63, &val_9))), 1);
- assert!(std::option::is_none(&div(&val_63, &val_0)), 1);
-
- // Inversion.
- assert!(eq(&val_minus_7, &neg(&val_7)), 1);
- assert!(std::option::is_none(&inv(&val_0)), 1);
-
- // Squaring.
- let val_x = rand_insecure();
- assert!(eq(&mul(&val_x, &val_x), &sqr(&val_x)), 1);
-
- // Downcasting.
- assert!(eq(&zero(), &std::option::extract(&mut downcast(&val_1))), 1);
- }
-
- #[test_only]
- const R_SERIALIZED: vector = x"01000000fffffffffe5bfeff02a4bd5305d8a10908d83933487d9d2953a7ed73";
- #[test_only]
- const G1_INF_SERIALIZED_COMP: vector = x"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const G1_INF_SERIALIZED_UNCOMP: vector = x"400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const G1_GENERATOR_SERIALIZED_COMP: vector = x"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb";
- #[test_only]
- const G1_GENERATOR_SERIALIZED_UNCOMP: vector = x"17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1";
- #[test_only]
- const G1_GENERATOR_MUL_BY_7_SERIALIZED_COMP: vector = x"b928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7";
- #[test_only]
- const G1_GENERATOR_MUL_BY_7_SERIALIZED_UNCOMP: vector = x"1928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7108dadbaa4b636445639d5ae3089b3c43a8a1d47818edd1839d7383959a41c10fdc66849cfa1b08c5a11ec7e28981a1c";
- #[test_only]
- const G1_GENERATOR_MUL_BY_7_NEG_SERIALIZED_COMP: vector = x"9928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb7";
- #[test_only]
- const G1_GENERATOR_MUL_BY_7_NEG_SERIALIZED_UNCOMP: vector = x"1928f3beb93519eecf0145da903b40a4c97dca00b21f12ac0df3be9116ef2ef27b2ae6bcd4c5bc2d54ef5a70627efcb70973642f94c9b055f4e1d20812c1f91329ed2e3d71f635a72d599a679d0cda1320e597b4e1b24f735fed1381d767908f";
-
- #[test(fx = @std)]
- fun test_g1affine(fx: signer) {
- enable_cryptography_algebra_natives(&fx);
-
- // Constants.
- assert!(R_SERIALIZED == order(), 1);
- let point_at_infinity = zero();
- let generator = one();
-
- // Serialization/deserialization.
- assert!(G1_GENERATOR_SERIALIZED_UNCOMP == serialize(&generator), 1);
- assert!(G1_GENERATOR_SERIALIZED_COMP == serialize(&generator), 1);
- let generator_from_comp = std::option::extract(&mut deserialize(&G1_GENERATOR_SERIALIZED_COMP
- ));
- let generator_from_uncomp = std::option::extract(&mut deserialize(&G1_GENERATOR_SERIALIZED_UNCOMP
- ));
- assert!(eq(&generator, &generator_from_comp), 1);
- assert!(eq(&generator, &generator_from_uncomp), 1);
-
- // Deserialization should fail if given a byte array of correct size but the value is not a member.
- assert!(std::option::is_none(&deserialize(&x"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), 1);
-
- // Deserialization should fail if given a byte array of wrong size.
- assert!(std::option::is_none(&deserialize(&x"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), 1);
-
- assert!(
- G1_INF_SERIALIZED_UNCOMP == serialize(&point_at_infinity), 1);
- assert!(G1_INF_SERIALIZED_COMP == serialize(&point_at_infinity), 1);
- let inf_from_uncomp = std::option::extract(&mut deserialize(&G1_INF_SERIALIZED_UNCOMP
- ));
- let inf_from_comp = std::option::extract(&mut deserialize(&G1_INF_SERIALIZED_COMP
- ));
- assert!(eq(&point_at_infinity, &inf_from_comp), 1);
- assert!(eq(&point_at_infinity, &inf_from_uncomp), 1);
-
- let point_7g_from_uncomp = std::option::extract(&mut deserialize(&G1_GENERATOR_MUL_BY_7_SERIALIZED_UNCOMP
- ));
- let point_7g_from_comp = std::option::extract(&mut deserialize(&G1_GENERATOR_MUL_BY_7_SERIALIZED_COMP
- ));
- assert!(eq(&point_7g_from_comp, &point_7g_from_uncomp), 1);
-
- // Deserialization should fail if given a point on the curve but off its prime-order subgroup, e.g., `(0,2)`.
- assert!(std::option::is_none(&deserialize(&x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002")), 1);
- assert!(std::option::is_none(&deserialize(&x"800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")), 1);
-
- // Deserialization should fail if given a valid point in (Fq,Fq) but not on the curve.
- assert!(std::option::is_none(&deserialize(&x"8959e137e0719bf872abb08411010f437a8955bd42f5ba20fca64361af58ce188b1adb96ef229698bb7860b79e24ba12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")), 1);
-
- // Deserialization should fail if given an invalid point (x not in Fq).
- assert!(std::option::is_none(&deserialize(&x"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa76e9853b35f5c9b2002d9e5833fd8f9ab4cd3934a4722a06f6055bfca720c91629811e2ecae7f0cf301b6d07898a90f")), 1);
- assert!(std::option::is_none(&deserialize(&x"9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), 1);
-
- // Deserialization should fail if given a byte array of wrong size.
- assert!(std::option::is_none(&deserialize(&x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab")), 1);
- assert!(std::option::is_none(&deserialize(&x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab")), 1);
-
- // Scalar multiplication.
- let scalar_7 = from_u64(7);
- let point_7g_calc = scalar_mul(&generator, &scalar_7);
- assert!(eq(&point_7g_calc, &point_7g_from_comp), 1);
- assert!(G1_GENERATOR_MUL_BY_7_SERIALIZED_UNCOMP == serialize(&point_7g_calc), 1);
- assert!(G1_GENERATOR_MUL_BY_7_SERIALIZED_COMP == serialize( &point_7g_calc), 1);
-
- // Multi-scalar multiplication.
- let num_entries = 1;
- while (num_entries < 10) {
- let scalars = rand_vector(num_entries);
- let elements = rand_vector(num_entries);
-
- let expected = zero();
- let i = 0;
- while (i < num_entries) {
- let element = std::vector::borrow(&elements, i);
- let scalar = std::vector::borrow(&scalars, i);
- expected = add(&expected, &scalar_mul(element, scalar));
- i = i + 1;
- };
-
- let actual = multi_scalar_mul(&elements, &scalars);
- assert!(eq(&expected, &actual), 1);
-
- num_entries = num_entries + 1;
- };
-
- // Doubling.
- let scalar_2 = from_u64(2);
- let point_2g = scalar_mul(&generator, &scalar_2);
- let point_double_g = double(&generator);
- assert!(eq(&point_2g, &point_double_g), 1);
-
- // Negation.
- let point_minus_7g_calc = neg(&point_7g_calc);
- assert!(G1_GENERATOR_MUL_BY_7_NEG_SERIALIZED_COMP == serialize(&point_minus_7g_calc), 1);
- assert!(G1_GENERATOR_MUL_BY_7_NEG_SERIALIZED_UNCOMP == serialize(&point_minus_7g_calc), 1);
-
- // Addition.
- let scalar_9 = from_u64(9);
- let point_9g = scalar_mul(&generator, &scalar_9);
- let point_2g = scalar_mul(&generator, &scalar_2);
- let point_2g_calc = add(&point_minus_7g_calc, &point_9g);
- assert!(eq(&point_2g, &point_2g_calc), 1);
-
- // Subtraction.
- assert!(eq(&point_9g, &sub(&point_2g, &point_minus_7g_calc)), 1);
-
- // Hash-to-group using suite `BLS12381G1_XMD:SHA-256_SSWU_RO_`.
- // Test vectors source: https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#name-bls12381g1_xmdsha-256_sswu_
- let actual = hash_to(&b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_", &b"");
- let expected = std::option::extract(&mut deserialize(&x"052926add2207b76ca4fa57a8734416c8dc95e24501772c814278700eed6d1e4e8cf62d9c09db0fac349612b759e79a108ba738453bfed09cb546dbb0783dbb3a5f1f566ed67bb6be0e8c67e2e81a4cc68ee29813bb7994998f3eae0c9c6a265"));
- assert!(eq(&expected, &actual), 1);
- let actual = hash_to(&b"QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_", &b"abcdef0123456789");
- let expected = std::option::extract(&mut deserialize(&x"11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf268c263ddd57a6a27200a784cbc248e84f357ce82d9803a87ae2caf14e8ee52e51fa2ed8eefe80f02457004ba4d486d6aa1f517c0889501dc7413753f9599b099ebcbbd2d709"));
- assert!(eq(&expected, &actual), 1);
- }
-
- #[test_only]
- const G2_INF_SERIALIZED_UNCOMP: vector = x"400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const G2_INF_SERIALIZED_COMP: vector = x"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
- #[test_only]
- const G2_GENERATOR_SERIALIZED_UNCOMP: vector = x"13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801";
- #[test_only]
- const G2_GENERATOR_SERIALIZED_COMP: vector = x"93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8";
- #[test_only]
- const G2_GENERATOR_MUL_BY_7_SERIALIZED_UNCOMP: vector = x"0d0273f6bf31ed37c3b8d68083ec3d8e20b5f2cc170fa24b9b5be35b34ed013f9a921f1cad1644d4bdb14674247234c8049cd1dbb2d2c3581e54c088135fef36505a6823d61b859437bfc79b617030dc8b40e32bad1fa85b9c0f368af6d38d3c05ecf93654b7a1885695aaeeb7caf41b0239dc45e1022be55d37111af2aecef87799638bec572de86a7437898efa702008b7ae4dbf802c17a6648842922c9467e460a71c88d393ee7af356da123a2f3619e80c3bdcc8e2b1da52f8cd9913ccdd";
- #[test_only]
- const G2_GENERATOR_MUL_BY_7_SERIALIZED_COMP: vector = x"8d0273f6bf31ed37c3b8d68083ec3d8e20b5f2cc170fa24b9b5be35b34ed013f9a921f1cad1644d4bdb14674247234c8049cd1dbb2d2c3581e54c088135fef36505a6823d61b859437bfc79b617030dc8b40e32bad1fa85b9c0f368af6d38d3c";
- #[test_only]
- const G2_GENERATOR_MUL_BY_7_NEG_SERIALIZED_UNCOMP: vector = x"0d0273f6bf31ed37c3b8d68083ec3d8e20b5f2cc170fa24b9b5be35b34ed013f9a921f1cad1644d4bdb14674247234c8049cd1dbb2d2c3581e54c088135fef36505a6823d61b859437bfc79b617030dc8b40e32bad1fa85b9c0f368af6d38d3c141418b3e4c84511f485fcc78b80b8bc623d6f3f1282e6da09f9c1860402272ba7129c72c4fcd2174f8ac87671053a8b1149639c79ffba82a4b71f73b11f186f8016a4686ab17ed0ec3d7bc6e476c6ee04c3f3c2d48b1d4ddfac073266ebddce";
- #[test_only]
- const G2_GENERATOR_MUL_BY_7_NEG_SERIALIZED_COMP: vector = x"ad0273f6bf31ed37c3b8d68083ec3d8e20b5f2cc170fa24b9b5be35b34ed013f9a921f1cad1644d4bdb14674247234c8049cd1dbb2d2c3581e54c088135fef36505a6823d61b859437bfc79b617030dc8b40e32bad1fa85b9c0f368af6d38d3c";
-
- #[test(fx = @std)]
- fun test_g2affine(fx: signer) {
- enable_cryptography_algebra_natives(&fx);
-
- // Special constants.
- assert!(R_SERIALIZED == order(), 1);
- let point_at_infinity = zero();
- let generator = one();
-
- // Serialization/deserialization.
- assert!(G2_GENERATOR_SERIALIZED_COMP == serialize(&generator), 1);
- assert!(G2_GENERATOR_SERIALIZED_UNCOMP == serialize(&generator), 1);
- let generator_from_uncomp = std::option::extract(&mut deserialize(&G2_GENERATOR_SERIALIZED_UNCOMP
- ));
- let generator_from_comp = std::option::extract(&mut deserialize(&G2_GENERATOR_SERIALIZED_COMP
- ));
- assert!(eq(&generator, &generator_from_comp), 1);
- assert!(eq(&generator, &generator_from_uncomp), 1);
- assert!(G2_INF_SERIALIZED_UNCOMP == serialize(&point_at_infinity), 1);
- assert!(G2_INF_SERIALIZED_COMP == serialize(&point_at_infinity), 1);
- let inf_from_uncomp = std::option::extract(&mut deserialize(&G2_INF_SERIALIZED_UNCOMP));
- let inf_from_comp = std::option::extract(&mut deserialize(&G2_INF_SERIALIZED_COMP));
- assert!(eq(&point_at_infinity, &inf_from_comp), 1);
- assert!(eq(&point_at_infinity, &inf_from_uncomp), 1);
- let point_7g_from_uncomp = std::option::extract(&mut deserialize(&G2_GENERATOR_MUL_BY_7_SERIALIZED_UNCOMP
- ));
- let point_7g_from_comp = std::option::extract(&mut deserialize(&G2_GENERATOR_MUL_BY_7_SERIALIZED_COMP
- ));
- assert!(eq(&point_7g_from_comp, &point_7g_from_uncomp), 1);
-
- // Deserialization should fail if given a point on the curve but not in the prime-order subgroup.
- assert!(std::option::is_none(&deserialize(&x"f037d4ccd5ee751eba1c1fd4c7edbb76d2b04c3a1f3f554827cf37c3acbc2dbb7cdb320a2727c2462d6c55ca1f637707b96eeebc622c1dbe7c56c34f93887c8751b42bd04f29253a82251c192ef27ece373993b663f4360505299c5bd18c890ddd862a6308796bf47e2265073c1f7d81afd69f9497fc1403e2e97a866129b43b672295229c21116d4a99f3e5c2ae720a31f181dbed8a93e15f909c20cf69d11a8879adbbe6890740def19814e6d4ed23fb0dcbd79291655caf48b466ac9cae04")), 1);
- assert!(std::option::is_none(&deserialize(&x"f037d4ccd5ee751eba1c1fd4c7edbb76d2b04c3a1f3f554827cf37c3acbc2dbb7cdb320a2727c2462d6c55ca1f637707b96eeebc622c1dbe7c56c34f93887c8751b42bd04f29253a82251c192ef27ece373993b663f4360505299c5bd18c890d")), 1);
-
- // Deserialization should fail if given a valid point in (Fq2,Fq2) but not on the curve.
- assert!(std::option::is_none(&deserialize(&x"f037d4ccd5ee751eba1c1fd4c7edbb76d2b04c3a1f3f554827cf37c3acbc2dbb7cdb320a2727c2462d6c55ca1f637707b96eeebc622c1dbe7c56c34f93887c8751b42bd04f29253a82251c192ef27ece373993b663f4360505299c5bd18c890d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")), 1);
-
- // Deserialization should fail if given an invalid point (x not in Fq2).
- assert!(std::option::is_none(&deserialize(&x"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdd862a6308796bf47e2265073c1f7d81afd69f9497fc1403e2e97a866129b43b672295229c21116d4a99f3e5c2ae720a31f181dbed8a93e15f909c20cf69d11a8879adbbe6890740def19814e6d4ed23fb0dcbd79291655caf48b466ac9cae04")), 1);
- assert!(std::option::is_none(&deserialize(&x"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), 1);
-
- // Deserialization should fail if given a byte array of wrong size.
- assert!(std::option::is_none(&deserialize(&x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab")), 1);
- assert!(std::option::is_none(&deserialize(&x"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab")), 1);
-
- // Scalar multiplication.
- let scalar_7 = from_u64(7);
- let point_7g_calc = scalar_mul(&generator, &scalar_7);
- assert!(eq(&point_7g_calc, &point_7g_from_comp), 1);
- assert!(G2_GENERATOR_MUL_BY_7_SERIALIZED_UNCOMP == serialize(&point_7g_calc), 1);
- assert!(G2_GENERATOR_MUL_BY_7_SERIALIZED_COMP == serialize(&point_7g_calc), 1);
-
- // Multi-scalar multiplication.
- let num_entries = 1;
- while (num_entries < 10) {
- let scalars = rand_vector(num_entries);
- let elements = rand_vector(num_entries);
-
- let expected = zero();
- let i = 0;
- while (i < num_entries) {
- let element = std::vector::borrow(&elements, i);
- let scalar = std::vector::borrow(&scalars, i);
- expected = add(&expected, &scalar_mul(element, scalar));
- i = i + 1;
- };
-
- let actual = multi_scalar_mul(&elements, &scalars);
- assert!(eq(&expected, &actual), 1);
-
- num_entries = num_entries + 1;
- };
-
- // Doubling.
- let scalar_2 = from_u64(2);
- let point_2g = scalar_mul(&generator, &scalar_2);
- let point_double_g = double(&generator);
- assert!(eq(&point_2g, &point_double_g), 1);
-
- // Negation.
- let point_minus_7g_calc = neg(&point_7g_calc);
- assert!(G2_GENERATOR_MUL_BY_7_NEG_SERIALIZED_COMP == serialize(&point_minus_7g_calc), 1);
- assert!(G2_GENERATOR_MUL_BY_7_NEG_SERIALIZED_UNCOMP == serialize(&point_minus_7g_calc), 1);
-
- // Addition.
- let scalar_9 = from_u64