Skip to content

Commit

Permalink
[tests] Add AIP-80 specs (#562)
Browse files Browse the repository at this point in the history
Add aip-80 specs

Co-authored-by: Greg Nazario <[email protected]>
  • Loading branch information
GhostWalker562 and gregnazario authored Nov 1, 2024
1 parent 15e238a commit 65a280e
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 0 deletions.
60 changes: 60 additions & 0 deletions tests/features/crypto_private_keys.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Feature: Cryptographic Private Keys
"""
Cryptographic private keys are keys that use asymmetric cryptography to sign and verify messages.
This specifications covers the following:
* Specifications for Ed25519 and Secp256k1 private keys.
* AIP-80 compliant formatting and parsing of bytes, hex strings, and AIP-80 compliant strings. Read about AIP-80 here: https://github.com/aptos-foundation/AIPs/blob/main/aips/aip-80.md
"""

Scenario Outline: It must format a HexString to an AIP-80 compliant string
Given key <key> hexstring <value>
When I format to aip-80
Then the result should be aip80_string <formatted>

Examples:
| key | value | formatted |
| ed25519 | 0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 | ed25519-priv-0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 |
| secp256k1 | 0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e | secp256k1-priv-0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e |

Scenario Outline: It must accept a HexString and derive the private key
Given key <key> hexstring <value>
When I derive the private key
Then the result should be aip80_string <formatted>

Examples:
| key | value | formatted |
| ed25519 | 0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 | ed25519-priv-0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 |
| secp256k1 | 0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e | secp256k1-priv-0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e |

Scenario Outline: It must accept bytes and derive the private key
Given key <key> bytes <value>
When I derive the private key
Then the result should be aip80_string <formatted>

Examples:
| key | value | formatted |
| ed25519 | c5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 | ed25519-priv-0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 |
| secp256k1 | d107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e | secp256k1-priv-0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e |

Scenario Outline: It must accept AIP-80 compliant strings and derive the private key
Given key <key> aip80_string <value>
When I derive the private key
Then the result should be aip80_string <formatted>

Examples:
| key | value | formatted |
| ed25519 | ed25519-priv-0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 | ed25519-priv-0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 |
| secp256k1 | secp256k1-priv-0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e | secp256k1-priv-0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e |

Scenario Outline: It should throw when an invalid AIP-80 string is provided
Given key <key> aip80_string <value>
When I derive the private key
Then it should throw

Examples:
| key | value |
| ed25519 | ed25519-priv-0xINVALIDHEX |
| ed25519 | INVALIDPREFIX-0xc5338cd251c22daa8c9c9cc94f498cc8a5c7e1d2e75287a5dda91096fe64efa5 |
| secp256k1 | secp256k1-priv-0xINVALIDHEX |
| secp256k1 | INVALIDPREFIX-0xd107155adf816a0a94c6db3c9489c13ad8a1eda7ada2e558ba3bfa47c020347e |
74 changes: 74 additions & 0 deletions tests/step-definitions/crypto_private_keys.steps.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Given, Then, When } from "@cucumber/cucumber";
import { Ed25519PrivateKey, Hex, PrivateKey, PrivateKeyVariants, Secp256k1PrivateKey } from "../../dist/esm/index.mjs";
import assert from "assert";

/* eslint-disable func-names */

Given(
/^key (ed25519|secp256k1) (hexstring|bytes|aip80_string) (.*)$/,
function (keyType: string, valueType: string, value: string) {
switch (keyType) {
case "ed25519":
this.keyType = PrivateKeyVariants.Ed25519;
break;
case "secp256k1":
this.keyType = PrivateKeyVariants.Secp256k1;
break;
default:
throw new Error(`Unsupported key type: ${keyType}`);
}

switch (valueType) {
case "hexstring":
this.inputType = "hexstring";
this.input = value;
break;
case "bytes":
this.inputType = "bytes";
this.input = Hex.fromHexString(value).toUint8Array();
break;
case "aip80_string":
this.inputType = "aip80_string";
this.input = value;
break;
default:
throw new Error(`Unsupported value type: ${valueType}`);
}
},
);

When(/^I derive the private key$/, function () {
try {
switch (this.keyType) {
case PrivateKeyVariants.Ed25519:
this.result = new Ed25519PrivateKey(this.input, false).toAIP80String();
break;
case PrivateKeyVariants.Secp256k1:
this.result = new Secp256k1PrivateKey(this.input, false).toAIP80String();
break;
default:
throw new Error(`Unsupported key type: ${this.keyType}`);
}
} catch (error) {
this.error = error;
}
});

When(/^I format to aip-80$/, function () {
this.result = PrivateKey.formatPrivateKey(this.input, this.keyType);
});

Then(/^the result should be (aip80_string) (.*)$/, function (type: string, value: string) {
if (this.error) throw this.error;
switch (type) {
case "aip80_string":
assert.equal(this.result, value, `Expected ${value} to be ${this.result}`);
break;
default:
throw new Error(`Unsupported result type: ${type}`);
}
});

Then(/^it should throw$/, function () {
assert(this.error !== undefined, "Expected an error to be thrown");
});

0 comments on commit 65a280e

Please sign in to comment.