diff --git a/docs/book/src/blockchain-development/hashing_and_cryptography.md b/docs/book/src/blockchain-development/hashing_and_cryptography.md
index 21ccb5a1392..d4edeeb95a7 100644
--- a/docs/book/src/blockchain-development/hashing_and_cryptography.md
+++ b/docs/book/src/blockchain-development/hashing_and_cryptography.md
@@ -8,10 +8,54 @@ The Sway standard library provides easy access to a selection of cryptographic h
{{#include ../../../../examples/hashing/src/main.sw}}
```
-## Signature Recovery
+## Cryptographic Signature Recovery and Verification
+
+Fuel supports 3 asymmetric cryptographic signature schemes; `Secp256k1`, `Secp256r1`, and `Ed25519`.
+
+### Public Key Recovery
+
+Given a `Signature` and a sign `Message`, you can recover a `PublicKey`.
+
+```sway
+{{#include ../../../../examples/signatures/src/main.sw:public_key_recovery}}
+```
+
+### Signed Message Address Recovery
+
+Given a `Signature` and signed `Message`, you can recover a Fuel `Address`.
```sway
-{{#include ../../../../examples/signatures/src/main.sw}}
+{{#include ../../../../examples/signatures/src/main.sw:address_recovery}}
```
-> **Note**: Recovery of EVM addresses is also supported via `std::vm::evm`.
+#### Signed Message EVM Address Recovery
+
+Recovery of EVM addresses is also supported.
+
+```sway
+{{#include ../../../../examples/signatures/src/main.sw:evm_address_recovery}}
+```
+
+### Public Key Signature Verification
+
+Given a `Signature`, `PublicKey`, and `Message`, you can verify that the message was signed using the public key.
+
+```sway
+{{#include ../../../../examples/signatures/src/main.sw:signature_verification}}
+```
+
+### Address Signature Verification
+
+Given a `Signature`, `Address`, and `Message`, you can verify that the message was signed by the address.
+
+```sway
+{{#include ../../../../examples/signatures/src/main.sw:address_verification}}
+```
+
+#### EVM Address Signature Verification
+
+Recovery of EVM addresses verification is also supported.
+
+```sway
+{{#include ../../../../examples/signatures/src/main.sw:evm_address_verification}}
+```
diff --git a/examples/signatures/src/main.sw b/examples/signatures/src/main.sw
index 50f0e6bb88e..f74674b8202 100644
--- a/examples/signatures/src/main.sw
+++ b/examples/signatures/src/main.sw
@@ -1,22 +1,218 @@
script;
-use std::{b512::B512, ecr::{ec_recover, ec_recover_address, EcRecoverError}};
+fn main() {}
-const MSG_HASH = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+use std::{
+ crypto::{
+ ed25519::*,
+ message::*,
+ public_key::*,
+ secp256k1::*,
+ secp256r1::*,
+ signature::*,
+ },
+ hash::{
+ Hash,
+ sha256,
+ },
+ vm::evm::evm_address::EvmAddress,
+};
-fn main() {
- let hi = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
- let lo = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
- let signature: B512 = B512::from((hi, lo));
+fn public_key_recovery() {
+ // ANCHOR: public_key_recovery
+ // Secp256rk1 Public Key Recovery
+ let secp256k1_signature: Signature = Signature::Secp256k1(Secp256k1::from((
+ 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8,
+ 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678,
+ )));
+ let signed_message = Message::from(0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15);
+ // A recovered public key pair.
+ let secp256k1_public_key = secp256k1_signature.recover(signed_message);
+ assert(secp256k1_public_key.is_ok());
+ assert(
+ secp256k1_public_key
+ .unwrap() == PublicKey::from((
+ 0x41a55558a3486b6ee3878f55f16879c0798afd772c1506de44aba90d29b6e65c,
+ 0x341ca2e0a3d5827e78d838e35b29bebe2a39ac30b58999e1138c9467bf859965,
+ )),
+ );
+ // Secp256r1 Public Key Recovery
+ let secp256r1_signature = Signature::Secp256r1(Secp256r1::from((
+ 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac,
+ 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d,
+ )));
+ let signed_message = Message::from(0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323);
// A recovered public key pair.
- let public_key = ec_recover(signature, MSG_HASH);
+ let secp256r1_public_key = secp256r1_signature.recover(signed_message);
+ assert(secp256r1_public_key.is_ok());
+ assert(
+ secp256r1_public_key
+ .unwrap() == PublicKey::from((
+ 0xd6ea577a54ae42411fbc78d686d4abba2150ca83540528e4b868002e346004b2,
+ 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452,
+ )),
+ );
+ // ANCHOR_END: public_key_recovery
+}
+fn address_recovery() {
+ // ANCHOR: address_recovery
+ // Secp256k1 Address Recovery
+ let secp256k1_signature = Signature::Secp256k1(Secp256k1::from((
+ 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8,
+ 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678,
+ )));
+ let signed_message = Message::from(0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15);
// A recovered Fuel address.
- let result_address: Result
= ec_recover_address(signature, MSG_HASH);
- if let Ok(address) = result_address {
- log(address.bits());
- } else {
- revert(0);
- }
+ let secp256k1_address = secp256k1_signature.address(signed_message);
+ assert(secp256k1_address.is_ok());
+ assert(
+ secp256k1_address
+ .unwrap() == Address::from(0x02844f00cce0f608fa3f0f7408bec96bfd757891a6fda6e1fa0f510398304881),
+ );
+
+ // Secp256r1 Address Recovery
+ let secp256r1_signature = Signature::Secp256r1(Secp256r1::from((
+ 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c,
+ 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d,
+ )));
+ let signed_message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ // A recovered Fuel address.
+ let secp256r1_address = secp256r1_signature.address(signed_message);
+ assert(secp256r1_address.is_ok());
+ assert(
+ secp256r1_address
+ .unwrap() == Address::from(0xb4a5fabee8cc852084b71f17107e9c18d682033a58967027af0ab01edf2f9a6a),
+ );
+
+ // ANCHOR_END: address_recovery
+}
+
+fn evm_address_recovery() {
+ // ANCHOR: evm_address_recovery
+ // Secp256k1 EVM Address Recovery
+ let secp256k1_signature = Signature::Secp256k1(Secp256k1::from((
+ 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d,
+ )));
+ let signed_message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ // A recovered EVM address.
+ let secp256k1_evm_address = secp256k1_signature.evm_address(signed_message);
+ assert(secp256k1_evm_address.is_ok());
+ assert(
+ secp256k1_evm_address
+ .unwrap() == EvmAddress::from(0x0000000000000000000000000ec44cf95ce5051ef590e6d420f8e722dd160ecb),
+ );
+
+ // Secp256r1 EVM Address Recovery
+ let secp256r1_signature = Signature::Secp256r1(Secp256r1::from((
+ 0x62CDC20C0AB6AA7B91E63DA9917792473F55A6F15006BC99DD4E29420084A3CC,
+ 0xF4D99AF28F9D6BD96BDAAB83BFED99212AC3C7D06810E33FBB14C4F29B635414,
+ )));
+ let signed_message = Message::from(0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563);
+ // A recovered EVM address.
+ let secp256r1_evm_address = secp256r1_signature.evm_address(signed_message);
+ assert(secp256r1_evm_address.is_ok());
+ assert(
+ secp256r1_evm_address
+ .unwrap() == EvmAddress::from(0x000000000000000000000000408eb2d97ef0beda0a33848d9e052066667cb00a),
+ );
+ // ANCHOR_END: evm_address_recovery
+}
+
+fn signature_verification() {
+ // ANCHOR: signature_verification
+ // Secp256k1 Signature Verification
+ let secp256k1_signature = Signature::Secp256k1(Secp256k1::from((
+ 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8,
+ 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678,
+ )));
+ let secp256k1_public_key = PublicKey::from((
+ 0x41a55558a3486b6ee3878f55f16879c0798afd772c1506de44aba90d29b6e65c,
+ 0x341ca2e0a3d5827e78d838e35b29bebe2a39ac30b58999e1138c9467bf859965,
+ ));
+ let signed_message = Message::from(0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15);
+ // A verified public key
+ let secp256k1_verified = secp256k1_signature.verify(secp256k1_public_key, signed_message);
+ assert(secp256k1_verified.is_ok());
+
+ // Secp256r1 Signature Verification
+ let secp256r1_signature = Signature::Secp256r1(Secp256r1::from((
+ 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac,
+ 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d,
+ )));
+ let secp256r1_public_key = PublicKey::from((
+ 0xd6ea577a54ae42411fbc78d686d4abba2150ca83540528e4b868002e346004b2,
+ 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452,
+ ));
+ let signed_message = Message::from(0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323);
+ // A verified public key
+ let secp256r1_verified = secp256r1_signature.verify(secp256r1_public_key, signed_message);
+ assert(secp256r1_verified.is_ok());
+
+ // Ed25519 Signature Verification
+ let ed25519_public_key = PublicKey::from(0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10);
+ let ed25519_signature = Signature::Ed25519(Ed25519::from((
+ 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545,
+ 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00,
+ )));
+ let hashed_message = Message::from(sha256(b256::zero()));
+ // A verified public key
+ let ed25519_verified = ed25519_signature.verify(ed25519_public_key, hashed_message);
+ assert(ed25519_verified.is_ok());
+ // ANCHOR_END: signature_verification
+}
+
+fn address_verification() {
+ // ANCHOR: address_verification
+ // Secp256k1 Address Verification
+ let secp256k1_address = Address::from(0x02844f00cce0f608fa3f0f7408bec96bfd757891a6fda6e1fa0f510398304881);
+ let secp256k1_signature = Secp256k1::from((
+ 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8,
+ 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678,
+ ));
+ let signed_message = Message::from(0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15);
+ // A verified address
+ let secp256k1_verified = secp256k1_signature.verify_address(secp256k1_address, signed_message);
+ assert(secp256k1_verified.is_ok());
+
+ // Secp256r1 Address Verification
+ let secp256r1_address = Address::from(0xb4a5fabee8cc852084b71f17107e9c18d682033a58967027af0ab01edf2f9a6a);
+ let secp256r1_signature = Signature::Secp256r1(Secp256r1::from((
+ 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c,
+ 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d,
+ )));
+ let signed_message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ // A verified address
+ let secp256r1_verified = secp256r1_signature.verify_address(secp256r1_address, signed_message);
+ assert(secp256r1_verified.is_ok());
+
+ // ANCHOR_END: address_verification
+}
+
+fn evm_address_verification() {
+ // ANCHOR: evm_address_verification
+ // Secp256k1 Address Verification
+ let secp256k1_evm_address = EvmAddress::from(0x0000000000000000000000000ec44cf95ce5051ef590e6d420f8e722dd160ecb);
+ let secp256k1_signature = Signature::Secp256k1(Secp256k1::from((
+ 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d,
+ )));
+ let signed_message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ // A recovered EVM address.
+ let secp256k1_verified = secp256k1_signature.verify_evm_address(secp256k1_evm_address, signed_message);
+ assert(secp256k1_verified.is_ok());
+
+ // Secp256r1 Address Verification
+ let secp256r1_evm_address = EvmAddress::from(0x000000000000000000000000408eb2d97ef0beda0a33848d9e052066667cb00a);
+ let secp256r1_signature = Signature::Secp256r1(Secp256r1::from((
+ 0x62CDC20C0AB6AA7B91E63DA9917792473F55A6F15006BC99DD4E29420084A3CC,
+ 0xF4D99AF28F9D6BD96BDAAB83BFED99212AC3C7D06810E33FBB14C4F29B635414,
+ )));
+ let signed_message = Message::from(0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563);
+ // A recovered EVM address.
+ let secp256r1_verified = secp256r1_signature.verify_evm_address(secp256r1_evm_address, signed_message);
+ assert(secp256r1_verified.is_ok());
+ // ANCHOR_END: evm_address_verification
}
diff --git a/sway-lib-std/src/crypto.sw b/sway-lib-std/src/crypto.sw
new file mode 100644
index 00000000000..94cccb1e13c
--- /dev/null
+++ b/sway-lib-std/src/crypto.sw
@@ -0,0 +1,9 @@
+library;
+
+pub mod signature_error;
+pub mod message;
+pub mod public_key;
+pub mod ed25519;
+pub mod secp256k1;
+pub mod secp256r1;
+pub mod signature;
diff --git a/sway-lib-std/src/crypto/ed25519.sw b/sway-lib-std/src/crypto/ed25519.sw
new file mode 100644
index 00000000000..c8c57c5538c
--- /dev/null
+++ b/sway-lib-std/src/crypto/ed25519.sw
@@ -0,0 +1,210 @@
+library;
+
+use ::alloc::alloc_bytes;
+use ::b512::B512;
+use ::bytes::Bytes;
+use ::convert::{From, Into, TryFrom};
+use ::crypto::{message::Message, public_key::PublicKey, signature_error::SignatureError};
+use ::hash::*;
+use ::result::Result::{self, *};
+use ::option::Option::{self, *};
+
+/// An ed25519 signature.
+pub struct Ed25519 {
+ /// The underlying raw `[u8; 64]` data of the signature.
+ bits: [u8; 64],
+}
+
+impl Ed25519 {
+ /// Creates a zeroed out instances of a Ed25519 signature.
+ ///
+ /// # Returns
+ ///
+ /// [Ed25519] - A zero ed25519 signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Ed25519;
+ ///
+ /// fn foo() {
+ /// let new_ed25519 = Ed25519::new();
+ /// assert(new_ed25519.bits()[0] == 0u8);
+ /// assert(new_ed25519.bits()[63] == 0u8);
+ /// }
+ /// ```
+ pub fn new() -> Self {
+ Self {
+ bits: [0u8; 64],
+ }
+ }
+
+ /// Returns the underlying raw `[u8; 64]` data of the signature.
+ ///
+ /// # Returns
+ ///
+ /// * [[u8; 64]] - The raw data of the signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Ed25519;
+ ///
+ /// fn foo() -> {
+ /// let new_ed25519 = Ed25519::new();
+ /// assert(new_ed25519.bits()[0] == 0u8);
+ /// }
+ /// ```
+ pub fn bits(self) -> [u8; 64] {
+ self.bits
+ }
+
+ /// Verifies that a 32-byte curve25519 public key derived from the private key was used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// NOTE: This uses a 32-byte public key.
+ ///
+ /// # Arguments
+ ///
+ /// * `public_key`: [PublicKey] - The public key that signed the message.
+ /// * `message`: [Message] - The hashed signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - A verified result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::{crypto::{Ed25519, Signature, Message, PublicKey}, constants::ZERO_B256};
+ ///
+ /// fn foo() {
+ /// let signature: Ed25519 = Ed25519::from((
+ /// 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545,
+ /// 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00
+ /// ));
+ /// let message: Message = Message::from(0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323);
+ /// // Only 32 bytes are valid for 32-byte curve25519 public keys
+ /// let public_key: PublicKey = PublicKey::from(0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10);
+ ///
+ /// // A verified public key with signature
+ /// let verified = signature.verify(pub_key, msg_hash);
+ /// assert(verified.is_ok());
+ /// }
+ /// ```
+ pub fn verify(self, public_key: PublicKey, message: Message) -> Result<(), SignatureError> {
+ if public_key.bytes().len() != 32 {
+ return Err(SignatureError::InvalidPublicKey);
+ }
+
+ let was_error = asm(
+ buffer: public_key.bytes().ptr(),
+ sig: __addr_of(self),
+ hash: message.bytes().ptr(),
+ len: message.bytes().len(),
+ ) {
+ ed19 buffer sig hash len;
+ err
+ };
+
+ // check the $err register to see if the `ed19` opcode succeeded
+ if was_error == 1 {
+ Err(SignatureError::InvalidSignature)
+ } else {
+ Ok(())
+ }
+ }
+}
+
+impl From for Ed25519 {
+ fn from(bits: B512) -> Self {
+ Self {
+ bits: asm(bits: bits.bits()) {
+ bits: [u8; 64]
+ },
+ }
+ }
+}
+impl From<(b256, b256)> for Ed25519 {
+ fn from(components: (b256, b256)) -> Self {
+ Self {
+ bits: asm(components: components) {
+ components: [u8; 64]
+ },
+ }
+ }
+}
+
+impl From<[u8; 64]> for Ed25519 {
+ fn from(array: [u8; 64]) -> Self {
+ Self { bits: array }
+ }
+}
+
+impl TryFrom for Ed25519 {
+ fn try_from(bytes: Bytes) -> Option {
+ if bytes.len() != 64 {
+ return None;
+ }
+
+ let bits = asm(ptr: bytes.ptr()) {
+ ptr: [u8; 64]
+ };
+
+ Some(Self { bits })
+ }
+}
+
+impl Into for Ed25519 {
+ fn into(self) -> B512 {
+ let ptr = __addr_of(self.bits);
+ let b256_1 = asm(bits: ptr) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: ptr.add_uint_offset(32)) {
+ bits: b256
+ };
+ B512::from((b256_1, b256_2))
+ }
+}
+
+impl Into<(b256, b256)> for Ed25519 {
+ fn into(self) -> (b256, b256) {
+ let ptr = __addr_of(self.bits);
+ let b256_1 = asm(bits: ptr) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: ptr.add_uint_offset(32)) {
+ bits: b256
+ };
+ (b256_1, b256_2)
+ }
+}
+
+impl Into for Ed25519 {
+ fn into(self) -> Bytes {
+ Bytes::from(raw_slice::from_parts::(__addr_of(self.bits), 64))
+ }
+}
+
+impl core::ops::Eq for Ed25519 {
+ fn eq(self, other: Self) -> bool {
+ let mut iter = 0;
+ while iter < 64 {
+ if self.bits[iter] != other.bits[iter] {
+ return false;
+ }
+ iter += 1;
+ }
+
+ true
+ }
+}
+
+impl Hash for Ed25519 {
+ fn hash(self, ref mut state: Hasher) {
+ state.write(Bytes::from(raw_slice::from_parts::(__addr_of(self.bits), 64)));
+ }
+}
diff --git a/sway-lib-std/src/crypto/message.sw b/sway-lib-std/src/crypto/message.sw
new file mode 100644
index 00000000000..811051c02fa
--- /dev/null
+++ b/sway-lib-std/src/crypto/message.sw
@@ -0,0 +1,109 @@
+library;
+
+use ::b512::B512;
+use ::bytes::Bytes;
+use ::alloc::alloc_bytes;
+use ::convert::{From, TryFrom, TryInto};
+use ::option::Option::{self, *};
+use ::hash::*;
+
+/// Normalized (hashed) message authenticated by a signature.
+pub struct Message {
+ /// The underlying raw data of the message.
+ bytes: Bytes,
+}
+
+impl Message {
+ /// Creates a new instance of a Message.
+ ///
+ /// # Returns
+ ///
+ /// [Message] - A new, empty Message.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Message;
+ ///
+ /// fn foo() {
+ /// let new_message = Message::new();
+ /// assert(new_message.bytes().len() == 0);
+ /// }
+ /// ```
+ pub fn new() -> Self {
+ Self {
+ bytes: Bytes::new(),
+ }
+ }
+
+ /// Returns the underlying raw `Bytes` data of the signature.
+ ///
+ /// # Returns
+ ///
+ /// * [Bytes] - The raw data of the signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Message;
+ ///
+ /// fn foo() -> {
+ /// let new_message = Message::new();
+ /// assert(new_message.bytes().len() == 0);
+ /// }
+ /// ```
+ pub fn bytes(self) -> Bytes {
+ self.bytes
+ }
+}
+
+impl From for Message {
+ fn from(bits: b256) -> Self {
+ Self {
+ bytes: Bytes::from(bits),
+ }
+ }
+}
+
+impl From for Message {
+ fn from(bytes: Bytes) -> Self {
+ Self { bytes }
+ }
+}
+
+impl TryInto for Message {
+ fn try_into(self) -> Option {
+ if self.bytes.len() != 32 {
+ return None;
+ }
+
+ Some(asm(bits: self.bytes.ptr()) {
+ bits: b256
+ })
+ }
+}
+
+impl core::ops::Eq for Message {
+ fn eq(self, other: Self) -> bool {
+ if self.bytes.len() != other.bytes.len() {
+ return false;
+ }
+
+ let mut iter = 0;
+ while iter < self.bytes.len() {
+ if self.bytes.get(iter).unwrap() != other.bytes.get(iter).unwrap()
+ {
+ return false;
+ }
+ iter += 1;
+ }
+
+ true
+ }
+}
+
+impl Hash for Message {
+ fn hash(self, ref mut state: Hasher) {
+ state.write(self.bytes);
+ }
+}
diff --git a/sway-lib-std/src/crypto/public_key.sw b/sway-lib-std/src/crypto/public_key.sw
new file mode 100644
index 00000000000..b940395ebf0
--- /dev/null
+++ b/sway-lib-std/src/crypto/public_key.sw
@@ -0,0 +1,198 @@
+library;
+
+use ::b512::B512;
+use ::bytes::Bytes;
+use ::alloc::alloc_bytes;
+use ::constants::ZERO_B256;
+use ::convert::{From, TryFrom, TryInto};
+use ::option::Option::{self, *};
+use ::hash::*;
+
+/// Asymmetric public key, i.e. verifying key, in uncompressed form.
+///
+/// # Additional Information
+///
+/// It should be noted that while Secp256k1 and Secp256r1 uses 64 byte public keys, Ed25519 uses 32 byte public keys.
+pub struct PublicKey {
+ /// The underlying raw data of the public key.
+ bytes: Bytes,
+}
+
+impl PublicKey {
+ /// Creates a new instance of a PublicKey signature.
+ ///
+ /// # Returns
+ ///
+ /// [PublicKey] - A public key.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::PublicKey;
+ ///
+ /// fn foo() {
+ /// let new_key = PublicKey::new();
+ /// assert(new_key.bytes().len() == 0);
+ /// }
+ /// ```
+ pub fn new() -> Self {
+ Self {
+ bytes: Bytes::new(),
+ }
+ }
+
+ /// Returns the underlying raw `Bytes` data of the public key.
+ ///
+ /// # Returns
+ ///
+ /// * [Bytes] - The raw data of the public key.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::PublicKey;
+ ///
+ /// fn foo() -> {
+ /// let new_key = PublicKey::new();
+ /// assert(new_key.bytes().len() == 64);
+ /// }
+ /// ```
+ pub fn bytes(self) -> Bytes {
+ self.bytes
+ }
+
+ /// Returns whether the public key is the zero public key.
+ ///
+ /// # Returns
+ ///
+ /// * [bool] - `true` if the public key is zero, otherwise `false`.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::PublicKey;
+ ///
+ /// fn foo() -> {
+ /// let new_key = PublicKey::new();
+ /// assert(new_key.is_zero() == true);
+ /// }
+ /// ```
+ pub fn is_zero(self) -> bool {
+ let mut iter = 0;
+ while iter < self.bytes.len() {
+ if self.bytes.get(iter).unwrap() != 0 {
+ return false;
+ }
+ iter += 1;
+ }
+
+ true
+ }
+}
+
+impl From for PublicKey {
+ fn from(bits: B512) -> Self {
+ Self {
+ bytes: Bytes::from(raw_slice::from_parts::(__addr_of(bits), 64)),
+ }
+ }
+}
+
+impl From<(b256, b256)> for PublicKey {
+ fn from(components: (b256, b256)) -> Self {
+ Self {
+ bytes: Bytes::from(raw_slice::from_parts::(__addr_of(components), 64)),
+ }
+ }
+}
+
+// Used for Ed25519 signatures
+impl From for PublicKey {
+ fn from(bits: b256) -> Self {
+ Self {
+ bytes: Bytes::from(bits),
+ }
+ }
+}
+
+impl TryFrom for PublicKey {
+ fn try_from(bytes: Bytes) -> Option {
+ // Public key can only have a length of 32 or 64 bytes
+ if bytes.len() == 32 || bytes.len() == 64 {
+ Some(Self { bytes })
+ } else {
+ None
+ }
+ }
+}
+
+impl TryInto<(b256, b256)> for PublicKey {
+ fn try_into(self) -> Option<(b256, b256)> {
+ if self.bytes.len() != 64 {
+ return None;
+ }
+
+ let b256_1 = asm(bits: self.bytes.ptr()) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: self.bytes.ptr().add_uint_offset(32)) {
+ bits: b256
+ };
+
+ Some((b256_1, b256_2))
+ }
+}
+
+impl TryInto for PublicKey {
+ fn try_into(self) -> Option {
+ if self.bytes.len() != 64 {
+ return None;
+ }
+
+ let b256_1 = asm(bits: self.bytes.ptr()) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: self.bytes.ptr().add_uint_offset(32)) {
+ bits: b256
+ };
+ Some(B512::from((b256_1, b256_2)))
+ }
+}
+
+// Used for Ed25519 signatures
+impl TryInto for PublicKey {
+ fn try_into(self) -> Option {
+ if self.bytes.len() != 32 {
+ return None;
+ }
+
+ Some(asm(bits: self.bytes().ptr()) {
+ bits: b256
+ })
+ }
+}
+
+impl core::ops::Eq for PublicKey {
+ fn eq(self, other: Self) -> bool {
+ if self.bytes.len() != other.bytes.len() {
+ return false;
+ }
+
+ let mut iter = 0;
+ while iter < self.bytes.len() {
+ if self.bytes.get(iter).unwrap() != other.bytes.get(iter).unwrap()
+ {
+ return false;
+ }
+ iter += 1;
+ }
+
+ true
+ }
+}
+
+impl Hash for PublicKey {
+ fn hash(self, ref mut state: Hasher) {
+ state.write(self.bytes);
+ }
+}
diff --git a/sway-lib-std/src/crypto/secp256k1.sw b/sway-lib-std/src/crypto/secp256k1.sw
new file mode 100644
index 00000000000..2249df6ecad
--- /dev/null
+++ b/sway-lib-std/src/crypto/secp256k1.sw
@@ -0,0 +1,445 @@
+library;
+
+use ::address::Address;
+use ::alloc::alloc_bytes;
+use ::b512::B512;
+use ::bytes::Bytes;
+use ::convert::{From, Into, TryFrom};
+use ::crypto::{message::Message, public_key::PublicKey, signature_error::SignatureError};
+use ::hash::*;
+use ::registers::error;
+use ::result::Result::{self, *};
+use ::option::Option::{self, *};
+use ::vm::evm::evm_address::EvmAddress;
+
+/// A secp256k1 signature.
+pub struct Secp256k1 {
+ /// The underlying raw `[u8; 64]` data of the signature.
+ bits: [u8; 64],
+}
+
+impl Secp256k1 {
+ /// Creates a zeroed out instances of a Secp256k1 signature.
+ ///
+ /// # Returns
+ ///
+ /// [Secp256k1] - A zero secp256k1 signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Secp256k1;
+ ///
+ /// fn foo() {
+ /// let new_secp256k1 = Secp256k1::new();
+ /// assert(new_secp256k1.bits()[0] == 0u8);
+ /// assert(new_secp256k1.bits()[63] == 0u8);
+ /// }
+ /// ```
+ pub fn new() -> Self {
+ Self {
+ bits: [0u8; 64],
+ }
+ }
+
+ /// Returns the underlying raw `[u8; 64]` data of the signature.
+ ///
+ /// # Returns
+ ///
+ /// * [[u8; 64]] - The raw data of the signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Secp256k1;
+ ///
+ /// fn foo() -> {
+ /// let new_secp256k1 = Secp256k1::new();
+ /// assert(new_secp256k1.bits()[0] == 0u8);
+ /// }
+ /// ```
+ pub fn bits(self) -> [u8; 64] {
+ self.bits
+ }
+
+ /// Recover the public key derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Follows the Secp256k1 elliptical curve.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered public key or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, PublicKey, Secp256k1};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256k1 = Secp256k1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let public_key: PublicKey = PublicKey::from((
+ /// 0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E,
+ /// 0xC44415635160ACFC87A84300EED97928C949A2D958FC0947C535F7539C59AE75
+ /// ));
+ ///
+ /// // A recovered public key pair.
+ /// let result_public_key = signature.recover(message);
+ ///
+ /// assert(result_public_key.is_ok());
+ /// assert(result_public_key.unwrap() == public_key);
+ /// }
+ /// ```
+ pub fn recover(self, message: Message) -> Result {
+ let public_key_buffer = (b256::zero(), b256::zero());
+ let was_error = asm(
+ buffer: __addr_of(public_key_buffer),
+ sig: __addr_of(self),
+ hash: message.bytes().ptr(),
+ ) {
+ eck1 buffer sig hash;
+ err
+ };
+
+ // check the $err register to see if the `eck1` opcode succeeded
+ if was_error == 1 {
+ Err(SignatureError::UnrecoverablePublicKey)
+ } else {
+ Ok(PublicKey::from(public_key_buffer))
+ }
+ }
+
+ /// Recover the address derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Follows the Secp256k1 elliptical curve.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered Fuel address or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, Secp256k1};
+ ///
+ /// fn foo() {
+ /// let address = Address::from(0x7AAE2D980BE4C3275C72CE5B527FA23FFB97B766966559DD062E2B78FD9D3766);
+ /// let signature: Secp256k1 = Secp256k1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ ///
+ /// // A recovered Fuel address.
+ /// let result_address = signature.address(message);
+ ///
+ /// assert(result_address.is_ok());
+ /// assert(result_address.unwrap() == address);
+ /// }
+ /// ```
+ pub fn address(self, message: Message) -> Result {
+ let pub_key_result = Self::recover(self, message);
+
+ if let Err(e) = pub_key_result {
+ // propagate the error if it exists
+ Err(e)
+ } else {
+ let pub_key = pub_key_result.unwrap();
+ let address = sha256(pub_key);
+ Ok(Address::from(address))
+ }
+ }
+
+ /// Recover the EVM address derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Follows the Secp256k1 elliptical curve.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered evm address or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::{vm::evm::evm_address::EvmAddress, crypto::{Secp256k1, Message}};
+ ///
+ /// fn foo() {
+ /// let evm_address = EvmAddress::from(0x7AAE2D980BE4C3275C72CE5B527FA23FFB97B766966559DD062E2B78FD9D3766);
+ /// let signature: Secp256k1 = Secp256k1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// // A recovered evm address.
+ /// let result_address = signature.evm_address(message).unwrap();
+ /// assert(result_address.is_ok());
+ /// assert(result_address.unwrap() == evm_address);
+ /// }
+ /// ```
+ pub fn evm_address(self, message: Message) -> Result {
+ let pub_key_result = Self::recover(self, message);
+
+ if let Err(e) = pub_key_result {
+ // propagate the error if it exists
+ Err(e)
+ } else {
+ let pub_key = pub_key_result.unwrap();
+ // Note that EVM addresses are derived from the Keccak256 hash of the pubkey (not sha256)
+ let evm_address_hash = keccak256(pub_key);
+ Ok(EvmAddress::from(evm_address_hash))
+ }
+ }
+
+ /// Verify that a signature matches given public key.
+ ///
+ /// # Arguments
+ ///
+ /// * `public_key`: [PublicKey] - The public key to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, PublicKey, Secp256k1};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256k1 = Secp256k1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let public_key: PublicKey = PublicKey::from((
+ /// 0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E,
+ /// 0xC44415635160ACFC87A84300EED97928C949A2D958FC0947C535F7539C59AE75
+ /// ));
+ ///
+ /// // A valid result
+ /// let result = signature.verify(public_key, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify(self, public_key: PublicKey, message: Message) -> Result<(), SignatureError> {
+ if public_key.bytes().len() != 64 {
+ return Err(SignatureError::InvalidPublicKey);
+ }
+
+ let pub_key_result = Self::recover(self, message);
+
+ if let Err(e) = pub_key_result {
+ // propagate the error if it exists
+ Err(e)
+ } else if pub_key_result.unwrap() == public_key {
+ Ok(())
+ } else {
+ Err(SignatureError::InvalidSignature)
+ }
+ }
+
+ /// Verify that an evm address matches given public key.
+ ///
+ /// # Arguments
+ ///
+ /// * `address`: [Address] - The address to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, Secp256k1};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256k1 = Secp256k1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let address = Address::from(0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E);
+ ///
+ /// // A valid result
+ /// let result = signature.verify_address(address, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify_address(self, address: Address, message: Message) -> Result<(), SignatureError> {
+ let address_result = Self::address(self, message);
+
+ if let Err(e) = address_result {
+ // propagate the error if it exists
+ Err(e)
+ } else if address_result.unwrap() == address {
+ Ok(())
+ } else {
+ Err(SignatureError::InvalidSignature)
+ }
+ }
+
+ /// Verify that an address matches given public key.
+ ///
+ /// # Arguments
+ ///
+ /// * `evm_address`: [EvmAddress] - The evm address to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::{crypto::{Message, Secp256k1}, vm::evm::evm_address::EvmAddress};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256k1 = Secp256k1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let evm_address = EvmAddress::from(0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E);
+ ///
+ /// // A valid result
+ /// let result = signature.verify_evm_address(evm_address, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify_evm_address(
+ self,
+ evm_address: EvmAddress,
+ message: Message,
+) -> Result<(), SignatureError> {
+ let evm_address_result = Self::evm_address(self, message);
+
+ if let Err(e) = evm_address_result {
+ // propagate the error if it exists
+ Err(e)
+ } else if evm_address_result.unwrap() == evm_address {
+ Ok(())
+ } else {
+ Err(SignatureError::InvalidSignature)
+ }
+ }
+}
+
+impl From for Secp256k1 {
+ fn from(bits: B512) -> Self {
+ Self {
+ bits: asm(bits: bits.bits()) {
+ bits: [u8; 64]
+ },
+ }
+ }
+}
+
+impl From<(b256, b256)> for Secp256k1 {
+ fn from(components: (b256, b256)) -> Self {
+ Self {
+ bits: asm(components: components) {
+ components: [u8; 64]
+ },
+ }
+ }
+}
+
+impl From<[u8; 64]> for Secp256k1 {
+ fn from(array: [u8; 64]) -> Self {
+ Self { bits: array }
+ }
+}
+
+impl TryFrom for Secp256k1 {
+ fn try_from(bytes: Bytes) -> Option {
+ if bytes.len() != 64 {
+ return None;
+ }
+
+ let bits = asm(ptr: bytes.ptr()) {
+ ptr: [u8; 64]
+ };
+
+ Some(Self { bits })
+ }
+}
+
+impl Into for Secp256k1 {
+ fn into(self) -> B512 {
+ let ptr = __addr_of(self.bits);
+ let b256_1 = asm(bits: ptr) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: ptr.add_uint_offset(32)) {
+ bits: b256
+ };
+ B512::from((b256_1, b256_2))
+ }
+}
+
+impl Into<(b256, b256)> for Secp256k1 {
+ fn into(self) -> (b256, b256) {
+ let ptr = __addr_of(self.bits);
+ let b256_1 = asm(bits: ptr) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: ptr.add_uint_offset(32)) {
+ bits: b256
+ };
+ (b256_1, b256_2)
+ }
+}
+
+impl Into for Secp256k1 {
+ fn into(self) -> Bytes {
+ Bytes::from(raw_slice::from_parts::(__addr_of(self.bits), 64))
+ }
+}
+
+impl core::ops::Eq for Secp256k1 {
+ fn eq(self, other: Self) -> bool {
+ let mut iter = 0;
+ while iter < 64 {
+ if self.bits[iter] != other.bits[iter] {
+ return false;
+ }
+ iter += 1;
+ }
+
+ true
+ }
+}
+
+impl Hash for Secp256k1 {
+ fn hash(self, ref mut state: Hasher) {
+ state.write(Bytes::from(raw_slice::from_parts::(__addr_of(self.bits), 64)));
+ }
+}
diff --git a/sway-lib-std/src/crypto/secp256r1.sw b/sway-lib-std/src/crypto/secp256r1.sw
new file mode 100644
index 00000000000..560e8558f87
--- /dev/null
+++ b/sway-lib-std/src/crypto/secp256r1.sw
@@ -0,0 +1,446 @@
+library;
+
+use ::address::Address;
+use ::alloc::alloc_bytes;
+use ::b512::B512;
+use ::bytes::Bytes;
+use ::convert::{From, Into, TryFrom};
+use ::crypto::{message::Message, public_key::PublicKey, signature_error::SignatureError};
+use ::hash::*;
+use ::registers::error;
+use ::result::Result::{self, *};
+use ::option::Option::{self, *};
+use ::vm::evm::evm_address::EvmAddress;
+
+/// A secp256r1 signature.
+pub struct Secp256r1 {
+ /// The underlying raw `[u8; 64]` data of the signature.
+ bits: [u8; 64],
+}
+
+impl Secp256r1 {
+ /// Creates a zeroed out instances of a Secp256r1 signature.
+ ///
+ /// # Returns
+ ///
+ /// [Secp256r1] - A zero secp256r1 signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Secp256r1;
+ ///
+ /// fn foo() {
+ /// let new_secp256r1 = Secp256r1::new();
+ /// assert(new_secp256r1.bits()[0] == 0u8);
+ /// assert(new_secp256r1.bits()[63] == 0u8);
+ /// }
+ /// ```
+ pub fn new() -> Self {
+ Self {
+ bits: [0u8; 64],
+ }
+ }
+
+ /// Returns the underlying raw `[u8; 64]` data of the signature.
+ ///
+ /// # Returns
+ ///
+ /// * [[u8; 64]] - The raw data of the signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::Secp256r1;
+ ///
+ /// fn foo() -> {
+ /// let new_secp256r1 = Secp256r1::new();
+ /// assert(new_secp256r1.bits()[0] == 0u8);
+ /// }
+ /// ```
+ pub fn bits(self) -> [u8; 64] {
+ self.bits
+ }
+
+ /// Recover the public key derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Follows the Secp256r1 elliptical curve.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered public key or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, PublicKey, Secp256r1};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256r1 = Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let public_key: PublicKey = PublicKey::from((
+ /// 0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E,
+ /// 0xC44415635160ACFC87A84300EED97928C949A2D958FC0947C535F7539C59AE75
+ /// ));
+ ///
+ /// // A recovered public key pair.
+ /// let result_public_key = signature.recover(message);
+ ///
+ /// assert(result_public_key.is_ok());
+ /// assert(result_public_key.unwrap() == public_key);
+ /// }
+ /// ```
+ pub fn recover(self, message: Message) -> Result {
+ let public_key_buffer = (b256::zero(), b256::zero());
+ let was_error = asm(
+ buffer: __addr_of(public_key_buffer),
+ sig: __addr_of(self),
+ hash: message.bytes().ptr(),
+ ) {
+ ecr1 buffer sig hash;
+ err
+ };
+
+ // check the $err register to see if the `ecr1` opcode succeeded
+ if was_error == 1 {
+ Err(SignatureError::UnrecoverablePublicKey)
+ } else {
+ Ok(PublicKey::from(public_key_buffer))
+ }
+ }
+
+ /// Recover the address derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Follows the Secp256r1 elliptical curve.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered Fuel address or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, Secp256r1};
+ ///
+ /// fn foo() {
+ /// let address = Address::from(0x7AAE2D980BE4C3275C72CE5B527FA23FFB97B766966559DD062E2B78FD9D3766);
+ /// let signature: Secp256r1 = Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ ///
+ /// // A recovered Fuel address.
+ /// let result_address = signature.address(message);
+ ///
+ /// assert(result_address.is_ok());
+ /// assert(result_address.unwrap() == address);
+ /// }
+ /// ```
+ pub fn address(self, message: Message) -> Result {
+ let pub_key_result = Self::recover(self, message);
+
+ if let Err(e) = pub_key_result {
+ // propagate the error if it exists
+ Err(e)
+ } else {
+ let pub_key = pub_key_result.unwrap();
+ let address = sha256(pub_key);
+ Ok(Address::from(address))
+ }
+ }
+
+ /// Recover the EVM address derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Follows the Secp256r1 elliptical curve.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered evm address or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::{vm::evm::evm_address::EvmAddress, crypto::{Secp256r1, Message}};
+ ///
+ /// fn foo() {
+ /// let evm_address = EvmAddress::from(0x7AAE2D980BE4C3275C72CE5B527FA23FFB97B766966559DD062E2B78FD9D3766);
+ /// let signature: Secp256r1 = Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ ///
+ /// // A recovered evm address.
+ /// let result_address = signature.evm_address(message).unwrap();
+ /// assert(result_address.is_ok());
+ /// assert(result_address.unwrap() == evm_address);
+ /// }
+ /// ```
+ pub fn evm_address(self, message: Message) -> Result {
+ let pub_key_result = Self::recover(self, message);
+
+ if let Err(e) = pub_key_result {
+ // propagate the error if it exists
+ Err(e)
+ } else {
+ let pub_key = pub_key_result.unwrap();
+ // Note that EVM addresses are derived from the Keccak256 hash of the pubkey (not sha256)
+ let evm_address_hash = keccak256(pub_key);
+ Ok(EvmAddress::from(evm_address_hash))
+ }
+ }
+
+ /// Verify that a signature matches given public key.
+ ///
+ /// # Arguments
+ ///
+ /// * `public_key`: [PublicKey] - The public key to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, PublicKey, Secp256r1};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256r1 = Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let public_key: PublicKey = PublicKey::from((
+ /// 0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E,
+ /// 0xC44415635160ACFC87A84300EED97928C949A2D958FC0947C535F7539C59AE75
+ /// ));
+ ///
+ /// // A valid result
+ /// let result = signature.verify(public_key, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify(self, public_key: PublicKey, message: Message) -> Result<(), SignatureError> {
+ if public_key.bytes().len() != 64 {
+ return Err(SignatureError::InvalidPublicKey);
+ }
+
+ let pub_key_result = Self::recover(self, message);
+
+ if let Err(e) = pub_key_result {
+ // propagate the error if it exists
+ Err(e)
+ } else if pub_key_result.unwrap() == public_key {
+ Ok(())
+ } else {
+ Err(SignatureError::InvalidSignature)
+ }
+ }
+
+ /// Verify that an signature matches given address.
+ ///
+ /// # Arguments
+ ///
+ /// * `address`: [Address] - The address to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, Secp256r1};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256r1 = Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let address = Address::from(0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E);
+ ///
+ /// // A valid result
+ /// let result = signature.verify_address(address, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify_address(self, address: Address, message: Message) -> Result<(), SignatureError> {
+ let address_result = Self::address(self, message);
+
+ if let Err(e) = address_result {
+ // propagate the error if it exists
+ Err(e)
+ } else if address_result.unwrap() == address {
+ Ok(())
+ } else {
+ Err(SignatureError::InvalidSignature)
+ }
+ }
+
+ /// Verify that an signature matches given evm address.
+ ///
+ /// # Arguments
+ ///
+ /// * `evm_address`: [EvmAddress] - The evm address to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::{crypto::{Message, Secp256r1}, vm::evm::evm_address::EvmAddress};
+ ///
+ /// fn foo() {
+ /// let signature: Secp256r1 = Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// ));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let evm_address = EvmAddress::from(0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E);
+ ///
+ /// // A valid result
+ /// let result = signature.verify_evm_address(evm_address, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify_evm_address(
+ self,
+ evm_address: EvmAddress,
+ message: Message,
+) -> Result<(), SignatureError> {
+ let evm_address_result = Self::evm_address(self, message);
+
+ if let Err(e) = evm_address_result {
+ // propagate the error if it exists
+ Err(e)
+ } else if evm_address_result.unwrap() == evm_address {
+ Ok(())
+ } else {
+ Err(SignatureError::InvalidSignature)
+ }
+ }
+}
+
+impl From for Secp256r1 {
+ fn from(bits: B512) -> Self {
+ Self {
+ bits: asm(bits: bits.bits()) {
+ bits: [u8; 64]
+ },
+ }
+ }
+}
+
+impl From<(b256, b256)> for Secp256r1 {
+ fn from(components: (b256, b256)) -> Self {
+ Self {
+ bits: asm(components: components) {
+ components: [u8; 64]
+ },
+ }
+ }
+}
+
+impl From<[u8; 64]> for Secp256r1 {
+ fn from(array: [u8; 64]) -> Self {
+ Self { bits: array }
+ }
+}
+
+impl TryFrom for Secp256r1 {
+ fn try_from(bytes: Bytes) -> Option {
+ if bytes.len() != 64 {
+ return None;
+ }
+
+ let bits = asm(ptr: bytes.ptr()) {
+ ptr: [u8; 64]
+ };
+
+ Some(Self { bits })
+ }
+}
+
+impl Into for Secp256r1 {
+ fn into(self) -> B512 {
+ let ptr = __addr_of(self.bits);
+ let b256_1 = asm(bits: ptr) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: ptr.add_uint_offset(32)) {
+ bits: b256
+ };
+ B512::from((b256_1, b256_2))
+ }
+}
+
+impl Into<(b256, b256)> for Secp256r1 {
+ fn into(self) -> (b256, b256) {
+ let ptr = __addr_of(self.bits);
+ let b256_1 = asm(bits: ptr) {
+ bits: b256
+ };
+ let b256_2 = asm(bits: ptr.add_uint_offset(32)) {
+ bits: b256
+ };
+ (b256_1, b256_2)
+ }
+}
+
+impl Into for Secp256r1 {
+ fn into(self) -> Bytes {
+ Bytes::from(raw_slice::from_parts::(__addr_of(self.bits), 64))
+ }
+}
+
+impl core::ops::Eq for Secp256r1 {
+ fn eq(self, other: Self) -> bool {
+ let mut iter = 0;
+ while iter < 64 {
+ if self.bits[iter] != other.bits[iter] {
+ return false;
+ }
+ iter += 1;
+ }
+
+ true
+ }
+}
+
+impl Hash for Secp256r1 {
+ fn hash(self, ref mut state: Hasher) {
+ state.write(Bytes::from(raw_slice::from_parts::(__addr_of(self.bits), 64)));
+ }
+}
diff --git a/sway-lib-std/src/crypto/signature.sw b/sway-lib-std/src/crypto/signature.sw
new file mode 100644
index 00000000000..e27fe7bf2c1
--- /dev/null
+++ b/sway-lib-std/src/crypto/signature.sw
@@ -0,0 +1,486 @@
+library;
+
+use ::address::Address;
+use ::crypto::{
+ ed25519::Ed25519,
+ message::Message,
+ public_key::PublicKey,
+ secp256k1::Secp256k1,
+ secp256r1::Secp256r1,
+ signature_error::SignatureError,
+};
+use ::option::Option::{self, *};
+use ::result::Result::{self, *};
+use ::vm::evm::evm_address::EvmAddress;
+
+/// An ECDSA signature.
+pub enum Signature {
+ Secp256k1: Secp256k1,
+ Secp256r1: Secp256r1,
+ Ed25519: Ed25519,
+}
+
+impl Signature {
+ /// Recover the public key derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Not applicable for Ed25519 signatures.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered public key or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, PublicKey, Secp256r1, Signature};
+ ///
+ /// fn foo() {
+ /// let signature: Signature = Signature::Secp256r1(Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// )));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let public_key: PublicKey = PublicKey::from((
+ /// 0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E,
+ /// 0xC44415635160ACFC87A84300EED97928C949A2D958FC0947C535F7539C59AE75
+ /// ));
+ ///
+ /// // A recovered public key pair.
+ /// let result_public_key = signature.recover(message);
+ ///
+ /// assert(result_public_key.is_ok());
+ /// assert(result_public_key.unwrap() == public_key);
+ /// }
+ /// ```
+ pub fn recover(self, message: Message) -> Result {
+ match self {
+ Self::Secp256k1(sig) => {
+ sig.recover(message)
+ },
+ Self::Secp256r1(sig) => {
+ sig.recover(message)
+ },
+ Self::Ed25519(_) => {
+ Err(SignatureError::InvalidOperation)
+ },
+ }
+ }
+
+ /// Recover the address derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Not applicable for Ed25519 signatures.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered Fuel address or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, Secp256r1, Signature};
+ ///
+ /// fn foo() {
+ /// let address = Address::from(0x7AAE2D980BE4C3275C72CE5B527FA23FFB97B766966559DD062E2B78FD9D3766);
+ /// let signature: Signature = Signature::Secp256r1(Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// )));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ ///
+ /// // A recovered Fuel address.
+ /// let result_address = signature.address(message);
+ ///
+ /// assert(result_address.is_ok());
+ /// assert(result_address.unwrap() == address);
+ /// }
+ /// ```
+ pub fn address(self, message: Message) -> Result {
+ match self {
+ Self::Secp256k1(sig) => {
+ sig.address(message)
+ },
+ Self::Secp256r1(sig) => {
+ sig.address(message)
+ },
+ Self::Ed25519(_) => {
+ Err(SignatureError::InvalidOperation)
+ },
+ }
+ }
+
+ /// Recover the EVM address derived from the private key used to sign a message.
+ /// Returns a `Result` to let the caller choose an error handling strategy.
+ ///
+ /// # Additional Information
+ ///
+ /// Not applicable for Ed25519 signatures.
+ ///
+ /// # Arguments
+ ///
+ /// * `message`: [Message] - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result] - The recovered evm address or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::{vm::evm::evm_address::EvmAddress, crypto::{Signature, Secp256k1, Message}};
+ ///
+ /// fn foo() {
+ /// let evm_address = EvmAddress::from(0x7AAE2D980BE4C3275C72CE5B527FA23FFB97B766966559DD062E2B78FD9D3766);
+ /// let signature: Signature = Signature::Secp256k1(Secp256k1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// )));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// // A recovered evm address.
+ /// let result_address = signature.evm_address(message).unwrap();
+ /// assert(result_address.is_ok());
+ /// assert(result_address.unwrap() == evm_address);
+ /// }
+ /// ```
+ pub fn evm_address(self, message: Message) -> Result {
+ match self {
+ Self::Secp256k1(sig) => {
+ sig.evm_address(message)
+ },
+ Self::Secp256r1(sig) => {
+ sig.evm_address(message)
+ },
+ Self::Ed25519(_) => {
+ Err(SignatureError::InvalidOperation)
+ },
+ }
+ }
+
+ /// Verify that a signature matches given public key.
+ ///
+ /// # Arguments
+ ///
+ /// * `public_key`: [PublicKey] - The public key to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, PublicKey, Secp256r1, Signature};
+ ///
+ /// fn foo() {
+ /// let signature: Signature = Signature::Secp256r1(Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// )));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let public_key: PublicKey = PublicKey::from((
+ /// 0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E,
+ /// 0xC44415635160ACFC87A84300EED97928C949A2D958FC0947C535F7539C59AE75
+ /// ));
+ ///
+ /// // A valid result
+ /// let result = signature.verify(public_key, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify(self, public_key: PublicKey, message: Message) -> Result<(), SignatureError> {
+ match self {
+ Self::Secp256k1(sig) => {
+ sig.verify(public_key, message)
+ },
+ Self::Secp256r1(sig) => {
+ sig.verify(public_key, message)
+ },
+ Self::Ed25519(sig) => {
+ sig.verify(public_key, message)
+ },
+ }
+ }
+
+ /// Verify that a signature matches given address.
+ ///
+ /// # Additional Information
+ ///
+ /// Not applicable for Ed25519 signatures.
+ ///
+ /// # Arguments
+ ///
+ /// * `address`: [Address] - The address to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Message, Secp256r1, Signature};
+ ///
+ /// fn foo() {
+ /// let signature: Signature = Signature::Secp256r1(Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// )));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let address = Address::from(0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E);
+ ///
+ /// // A valid result
+ /// let result = signature.verify_address(address, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify_address(self, address: Address, message: Message) -> Result<(), SignatureError> {
+ match self {
+ Self::Secp256k1(sig) => {
+ sig.verify_address(address, message)
+ },
+ Self::Secp256r1(sig) => {
+ sig.verify_address(address, message)
+ },
+ Self::Ed25519(_) => {
+ Err(SignatureError::InvalidOperation)
+ },
+ }
+ }
+
+ /// Verify that an signature matches given evm address.
+ ///
+ /// # Additional Information
+ ///
+ /// Not applicable for Ed25519 signatures.
+ ///
+ /// # Arguments
+ ///
+ /// * `evm_address`: [EvmAddress] - The evm address to verify against.
+ /// * `message`: Message - The signed data.
+ ///
+ /// # Returns
+ ///
+ /// * [Result<(), SignatureError>] - An Ok result or an error.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::{crypto::{Message, Secp256r1, Signature}, vm::evm::evm_address::EvmAddress};
+ ///
+ /// fn foo() {
+ /// let signature: Signature = Signature::Secp256r1(Secp256r1::from((
+ /// 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c,
+ /// 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d
+ /// )));
+ /// let message: Message = Message::from(0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323);
+ /// let evm_address = EvmAddress::from(0xD73A188181464CC84AE267E45041AEF6AB938F278E636AA1D02D3014C1BEF74E);
+ ///
+ /// // A valid result
+ /// let result = signature.verify_evm_address(evm_address, message);
+ /// assert(result.is_ok());
+ /// }
+ /// ```
+ pub fn verify_evm_address(
+ self,
+ evm_address: EvmAddress,
+ message: Message,
+) -> Result<(), SignatureError> {
+ match self {
+ Self::Secp256k1(sig) => {
+ sig.verify_evm_address(evm_address, message)
+ },
+ Self::Secp256r1(sig) => {
+ sig.verify_evm_address(evm_address, message)
+ },
+ Self::Ed25519(_) => {
+ Err(SignatureError::InvalidOperation)
+ },
+ }
+ }
+
+ /// Returns the `Secp256k1` of the `Signature`.
+ ///
+ /// # Returns
+ ///
+ /// * [Option] - `Some(Secp256k1)` if the underlying type is an `Secp256k1`, otherwise `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Signature, Secp256k1};
+ ///
+ /// fn foo() {
+ /// let signature = Signature::Secp256k1(Secp256k1::new());
+ /// let secp256k1 = signature.as_secp256k1();
+ /// assert(secp256k1 == Secp256k1::new());
+ /// }
+ /// ```
+ pub fn as_secp256k1(self) -> Option {
+ match self {
+ Self::Secp256k1(sig) => Some(sig),
+ Self::Secp256r1(_) => None,
+ Self::Ed25519(_) => None,
+ }
+ }
+
+ /// Returns the `Secp256r1` of the `Signature`.
+ ///
+ /// # Returns
+ ///
+ /// * [Option] - `Some(Secp256r1)` if the underlying type is an `Secp256r1`, otherwise `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Signature, Secp256r1};
+ ///
+ /// fn foo() {
+ /// let signature = Signature::Secp256r1(Secp256r1::new());
+ /// let secp256r1 = signature.as_secp256k1();
+ /// assert(secp256r1 == Secp256r1::new());
+ /// }
+ /// ```
+ pub fn as_secp256r1(self) -> Option {
+ match self {
+ Self::Secp256r1(sig) => Some(sig),
+ Self::Secp256k1(_) => None,
+ Self::Ed25519(_) => None,
+ }
+ }
+
+ /// Returns the `Ed25519` of the `Signature`.
+ ///
+ /// # Returns
+ ///
+ /// * [Option] - `Some(Ed25519)` if the underlying type is an `Ed25519`, otherwise `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Signature, Ed25519};
+ ///
+ /// fn foo() {
+ /// let signature = Signature::Ed25519(Ed25519::new());
+ /// let ed25519 = signature.as_secp256k1();
+ /// assert(ed25519 == Ed25519::new());
+ /// }
+ /// ```
+ pub fn as_ed25519(self) -> Option {
+ match self {
+ Self::Ed25519(sig) => Some(sig),
+ Self::Secp256k1(_) => None,
+ Self::Secp256r1(_) => None,
+ }
+ }
+
+ /// Returns whether the `Signature` represents an `Secp256k1`.
+ ///
+ /// # Returns
+ ///
+ /// * [bool] - Indicates whether the `Signature` holds an `Secp256k1`.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Signature, Secp256k1};
+ ///
+ /// fn foo() {
+ /// let signature = Signature::Secp256k1(Secp256k1::new());
+ /// assert(signature.is_secp256k1());
+ /// }
+ /// ```
+ pub fn is_secp256k1(self) -> bool {
+ match self {
+ Self::Secp256k1(_) => true,
+ Self::Secp256r1(_) => false,
+ Self::Ed25519(_) => false,
+ }
+ }
+
+ /// Returns whether the `Signature` represents an `Secp256r1`.
+ ///
+ /// # Returns
+ ///
+ /// * [bool] - Indicates whether the `Signature` holds an `Secp256r1`.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Signature, Secp256r1};
+ ///
+ /// fn foo() {
+ /// let signature = Signature::Secp256r1(Secp256r1::new());
+ /// assert(signature.is_secp256r1());
+ /// }
+ /// ```
+ pub fn is_secp256r1(self) -> bool {
+ match self {
+ Self::Secp256r1(_) => true,
+ Self::Secp256k1(_) => false,
+ Self::Ed25519(_) => false,
+ }
+ }
+
+ /// Returns whether the `Signature` represents an `Ed25519`.
+ ///
+ /// # Returns
+ ///
+ /// * [bool] - Indicates whether the `Signature` holds an `Ed25519`.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Signature, Ed25519};
+ ///
+ /// fn foo() {
+ /// let signature = Signature::Ed25519(Ed25519::new());
+ /// assert(signature.is_ed25519());
+ /// }
+ /// ```
+ pub fn is_ed25519(self) -> bool {
+ match self {
+ Self::Ed25519(_) => true,
+ Self::Secp256k1(_) => false,
+ Self::Secp256r1(_) => false,
+ }
+ }
+
+ /// Returns the underlying raw `[u8; 64]` data of the Signature.
+ ///
+ /// # Returns
+ ///
+ /// * [[u8; 64]] - The raw data of the signature.
+ ///
+ /// # Examples
+ ///
+ /// ```sway
+ /// use std::crypto::{Signature, Ed25519};
+ ///
+ /// fn foo() -> {
+ /// let my_signature = Signature::Ed25519(Ed25519::new());
+ /// assert(my_signature.bits()[0] == 0u8);
+ /// }
+ /// ```
+ pub fn bits(self) -> [u8; 64] {
+ match self {
+ Self::Secp256k1(sig) => sig.bits(),
+ Self::Secp256r1(sig) => sig.bits(),
+ Self::Ed25519(sig) => sig.bits(),
+ }
+ }
+}
diff --git a/sway-lib-std/src/crypto/signature_error.sw b/sway-lib-std/src/crypto/signature_error.sw
new file mode 100644
index 00000000000..53bd82b8b00
--- /dev/null
+++ b/sway-lib-std/src/crypto/signature_error.sw
@@ -0,0 +1,13 @@
+library;
+
+/// The error type used when a cryptographic signature function fails.
+pub enum SignatureError {
+ /// The error variant used when the recover fails.
+ UnrecoverablePublicKey: (),
+ /// The error variant used when the public key is of the wrong type.
+ InvalidPublicKey: (),
+ /// The error variant used when signature verification fails.
+ InvalidSignature: (),
+ /// The error varient used when an invalid operation was performed.
+ InvalidOperation: (),
+}
diff --git a/sway-lib-std/src/ecr.sw b/sway-lib-std/src/ecr.sw
index 236703603fa..33ac4fb9924 100644
--- a/sway-lib-std/src/ecr.sw
+++ b/sway-lib-std/src/ecr.sw
@@ -51,6 +51,7 @@ pub enum EcRecoverError {
/// assert(public_key.bits()[1] == pub_lo);
/// }
/// ```
+#[deprecated(note = "std::ecr has been replaced by std::crypto, and is no longer maintained")]
pub fn ec_recover(signature: B512, msg_hash: b256) -> Result {
let public_key = B512::new();
let was_error = asm(
@@ -104,6 +105,7 @@ pub fn ec_recover(signature: B512, msg_hash: b256) -> Result Result {
let public_key = B512::new();
let was_error = asm(
@@ -157,6 +159,7 @@ pub fn ec_recover_r1(signature: B512, msg_hash: b256) -> Result Result {
let len = msg.len();
@@ -213,6 +216,7 @@ pub fn ed_verify(public_key: b256, signature: B512, msg: Bytes) -> Result Result {
let pub_key_result = ec_recover(signature, msg_hash);
@@ -258,6 +262,7 @@ pub fn ec_recover_address(signature: B512, msg_hash: b256) -> Result Result {
let pub_key_result = ec_recover_r1(signature, msg_hash);
diff --git a/sway-lib-std/src/lib.sw b/sway-lib-std/src/lib.sw
index fc09e123cd6..fee5ce151cf 100644
--- a/sway-lib-std/src/lib.sw
+++ b/sway-lib-std/src/lib.sw
@@ -33,6 +33,7 @@ pub mod address;
pub mod identity;
pub mod ecr;
pub mod vm;
+pub mod crypto;
pub mod string;
pub mod r#storage;
pub mod block;
diff --git a/sway-lib-std/src/vm/evm/ecr.sw b/sway-lib-std/src/vm/evm/ecr.sw
index f66c148063e..57f0565824b 100644
--- a/sway-lib-std/src/vm/evm/ecr.sw
+++ b/sway-lib-std/src/vm/evm/ecr.sw
@@ -35,6 +35,7 @@ use ::vm::evm::evm_address::EvmAddress;
/// assert(result_address == evm_address);
/// }
/// ```
+#[deprecated(note = "std:vm::evm:ecr has been replaced by std::crypto, and is no longer maintained")]
pub fn ec_recover_evm_address(
signature: B512,
msg_hash: b256,
diff --git a/test/src/in_language_tests/Forc.toml b/test/src/in_language_tests/Forc.toml
index 839e204ad0a..2f399e112b0 100644
--- a/test/src/in_language_tests/Forc.toml
+++ b/test/src/in_language_tests/Forc.toml
@@ -10,6 +10,12 @@ members = [
"test_programs/bytes_inline_tests",
"test_programs/contract_id_inline_tests",
"test_programs/contract_id_contract_tests",
+ "test_programs/crypto_ed25519_inline_tests",
+ "test_programs/crypto_message_inline_tests",
+ "test_programs/crypto_public_key_inline_tests",
+ "test_programs/crypto_secp256k1_inline_tests",
+ "test_programs/crypto_secp256r1_inline_tests",
+ "test_programs/crypto_signature_inline_tests",
"test_programs/ecr_inline_tests",
"test_programs/flags_inline_tests",
"test_programs/hash_inline_tests",
diff --git a/test/src/in_language_tests/test_programs/crypto_ed25519_inline_tests/Forc.toml b/test/src/in_language_tests/test_programs/crypto_ed25519_inline_tests/Forc.toml
new file mode 100644
index 00000000000..6bc373a2aec
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_ed25519_inline_tests/Forc.toml
@@ -0,0 +1,8 @@
+[project]
+authors = ["Fuel Labs "]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "crypto_ed25519_inline_tests"
+
+[dependencies]
+std = { path = "../../../../../sway-lib-std" }
diff --git a/test/src/in_language_tests/test_programs/crypto_ed25519_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/crypto_ed25519_inline_tests/src/main.sw
new file mode 100644
index 00000000000..d0ca754bf81
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_ed25519_inline_tests/src/main.sw
@@ -0,0 +1,293 @@
+library;
+
+use std::{bytes::Bytes, b512::B512, crypto::{ed25519::*, public_key::*, message::*}, hash::{Hash, sha256}, vm::evm::evm_address::EvmAddress};
+
+#[test]
+fn ed25519_new() {
+ let new_ed25519 = Ed25519::new();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(new_ed25519.bits()[iter] == 0u8);
+ iter += 1;
+ }
+}
+
+#[test]
+fn ed25519_bits() {
+ let new_ed25519 = Ed25519::new();
+ let ed25519_bits = new_ed25519.bits();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(ed25519_bits[iter] == 0u8);
+ iter += 1;
+ }
+}
+
+#[test]
+fn ed25519__verify() {
+ let pub_key = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg = b256::zero();
+ let msg_hash = sha256(msg);
+ let hi = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key: PublicKey = PublicKey::from(pub_key);
+ let signature: Ed25519 = Ed25519::from((hi, lo));
+ let message: Message = Message::from(msg_hash);
+
+ // A verified public key with signature
+ let verified = signature.verify(public_key, message);
+ assert(verified.is_ok());
+
+ let pub_key_2 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_2 = b256::zero();
+ let msg_hash_2 = sha256(msg_2);
+ let hi_2 = b256::zero();
+ let lo_2 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_2: PublicKey = PublicKey::from(pub_key_2);
+ let signature_2: Ed25519 = Ed25519::from((hi_2, lo_2));
+ let message_2: Message = Message::from(msg_hash_2);
+
+ let verified_2 = signature_2.verify(public_key_2, message_2);
+ assert(verified_2.is_err());
+
+ let pub_key_3 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_3 = b256::zero();
+ let msg_hash_3 = sha256(msg_3);
+ let hi_3 = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo_3 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_3: PublicKey = PublicKey::from((pub_key_3, b256::zero()));
+ let signature_3: Ed25519 = Ed25519::from((hi_3, lo_3));
+ let message_3: Message = Message::from(msg_hash_3);
+
+ // A verified public key with signature
+ let verified_3 = signature_3.verify(public_key_3, message_3);
+ assert(verified_3.is_err());
+}
+
+#[test]
+fn ed25519_from_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let ed25519_1 = Ed25519::from(b512_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(ed25519_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let b512_2 = B512::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let ed25519_2 = Ed25519::from(b512_2);
+ assert(ed25519_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(ed25519_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let ed25519_3 = Ed25519::from(b512_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(ed25519_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn ed25519_from_b256_tuple() {
+ let ed25519_1 = Ed25519::from((b256::zero(), b256::zero()));
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(ed25519_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let ed25519_2 = Ed25519::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ assert(ed25519_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(ed25519_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let ed25519_3 = Ed25519::from((b256::max(), b256::max()));
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(ed25519_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn ed25519_from_u8_array() {
+ let array_1 = [
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ ];
+ let ed25519_1 = Ed25519::from(array_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(ed25519_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let array_2 = [
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
+ ];
+ let ed25519_2 = Ed25519::from(array_2);
+ assert(ed25519_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(ed25519_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let array_3 = [
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ ];
+ let ed25519_3 = Ed25519::from(array_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(ed25519_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn ed25519_try_from_bytes() {
+ let b256_tuple_1 = (b256::zero(), b256::zero());
+ let bytes_1 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_1), 64));
+ let ed25519_1 = Ed25519::try_from(bytes_1).unwrap();
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(ed25519_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let b256_tuple_2 = (b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001);
+ let bytes_2 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_2), 64));
+ let ed25519_2 = Ed25519::try_from(bytes_2).unwrap();
+ assert(ed25519_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(ed25519_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let b256_tuple_3 = (b256::max(), b256::max());
+ let bytes_3 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_3), 64));
+ let ed25519_3 = Ed25519::try_from(bytes_3).unwrap();
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(ed25519_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+
+ let bytes_4 = Bytes::new();
+ let ed25519_4 = Ed25519::try_from(bytes_4);
+ assert(ed25519_4.is_none());
+
+ let mut bytes_5 = Bytes::new();
+ bytes_5.push(0u8);
+ bytes_5.push(0u8);
+ bytes_5.push(0u8);
+ let ed25519_5 = Ed25519::try_from(bytes_5);
+ assert(ed25519_5.is_none());
+}
+
+#[test]
+fn ed25519_into_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let ed25519_1 = Ed25519::from(b512_1);
+ assert(>::into(ed25519_1) == b512_1);
+
+ let b512_2 = B512::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let ed25519_2 = Ed25519::from(b512_2);
+ assert(>::into(ed25519_2) == b512_2);
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let ed25519_3 = Ed25519::from(b512_3);
+ assert(>::into(ed25519_3) == b512_3);
+}
+
+#[test]
+fn ed25519_into_b256() {
+ let ed25519_1 = Ed25519::from((b256::zero(), b256::zero()));
+ let (result_1_1, result_2_1) = >::into(ed25519_1);
+ assert(result_1_1 == b256::zero());
+ assert(result_2_1 == b256::zero());
+
+ let ed25519_2 = Ed25519::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let (result_1_2, result_2_2): (b256, b256) = >::into(ed25519_2);
+ assert(result_1_2 == b256::zero());
+ assert(result_2_2 == 0x0000000000000000000000000000000000000000000000000000000000000001);
+
+ let ed25519_3 = Ed25519::from((b256::max(), b256::max()));
+ let (result_1_3, result_2_3): (b256, b256) = >::into(ed25519_3);
+ assert(result_1_3 == b256::max());
+ assert(result_2_3 == b256::max());
+}
+
+#[test]
+fn ed25519_into_bytes() {
+ let ed25519_1 = Ed25519::from((b256::zero(), b256::zero()));
+ let bytes_result_1: Bytes = >::into(ed25519_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(bytes_result_1.get(iter_1).unwrap() == 0u8);
+ iter_1 += 1;
+ }
+
+ let ed25519_2 = Ed25519::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let bytes_result_2: Bytes = >::into(ed25519_2);
+ assert(bytes_result_2.get(63).unwrap() == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(bytes_result_2.get(iter_2).unwrap() == 0u8);
+ iter_2 += 1;
+ }
+
+ let ed25519_3 = Ed25519::from((b256::max(), b256::max()));
+ let bytes_result_3: Bytes = >::into(ed25519_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(bytes_result_3.get(iter_3).unwrap() == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn ed25519_eq() {
+ let ed25519_1 = Ed25519::from((b256::zero(), b256::zero()));
+ let ed25519_2 = Ed25519::from((b256::zero(), b256::zero()));
+ let ed25519_3 = Ed25519::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let ed25519_4 = Ed25519::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let ed25519_5 = Ed25519::from((b256::max(), b256::max()));
+ let ed25519_6 = Ed25519::from((b256::max(), b256::max()));
+
+ assert(ed25519_1 == ed25519_2);
+ assert(ed25519_3 == ed25519_4);
+ assert(ed25519_5 == ed25519_6);
+
+ assert(ed25519_1 != ed25519_3);
+ assert(ed25519_1 != ed25519_5);
+
+ assert(ed25519_3 != ed25519_5);
+}
+
+#[test]
+fn ed25519_hash() {
+ let ed25519 = Ed25519::from((b256::zero(), b256::zero()));
+ let hash = sha256(ed25519);
+ assert(hash == 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b);
+}
diff --git a/test/src/in_language_tests/test_programs/crypto_message_inline_tests/Forc.toml b/test/src/in_language_tests/test_programs/crypto_message_inline_tests/Forc.toml
new file mode 100644
index 00000000000..1c08e06c3fe
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_message_inline_tests/Forc.toml
@@ -0,0 +1,8 @@
+[project]
+authors = ["Fuel Labs "]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "crypto_message_inline_tests"
+
+[dependencies]
+std = { path = "../../../../../sway-lib-std" }
diff --git a/test/src/in_language_tests/test_programs/crypto_message_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/crypto_message_inline_tests/src/main.sw
new file mode 100644
index 00000000000..283a271a549
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_message_inline_tests/src/main.sw
@@ -0,0 +1,210 @@
+library;
+
+use std::{bytes::Bytes, crypto::message::*, hash::{Hash, sha256}};
+
+#[test]
+fn message_new() {
+ let new_message = Message::new();
+
+ assert(new_message.bytes().len() == 0);
+ assert(new_message.bytes().capacity() == 0);
+}
+
+#[test]
+fn message_bytes() {
+ let new_message = Message::new();
+ let new_message_bytes = new_message.bytes();
+ assert(new_message_bytes.len() == 0);
+ assert(new_message_bytes.capacity() == 0);
+
+ let mut bytes = Bytes::new();
+ bytes.push(1u8);
+ bytes.push(3u8);
+ bytes.push(5u8);
+
+ let other_message = Message::from(bytes);
+ let other_message_bytes = other_message.bytes();
+ assert(other_message_bytes.len() == 3);
+ assert(other_message_bytes.get(0).unwrap() == 1u8);
+ assert(other_message_bytes.get(1).unwrap() == 3u8);
+ assert(other_message_bytes.get(2).unwrap() == 5u8);
+}
+
+#[test]
+fn message_from_b256() {
+ let zero_b256 = b256::zero();
+ let max_b256 = b256::max();
+ let other_b256 = 0x0000000000000000000000000000000000000000000000000000000000000001;
+
+ let zero_message = Message::from(zero_b256);
+ assert(zero_message.bytes().len() == 32);
+ let mut iter_1 = 0;
+ while iter_1 < zero_message.bytes().len() {
+ assert(zero_message.bytes().get(iter_1).unwrap() == 0u8);
+ iter_1 += 1;
+ }
+
+ let max_message = Message::from(max_b256);
+ assert(max_message.bytes().len() == 32);
+ let mut iter_2 = 0;
+ while iter_2 < max_message.bytes().len() {
+ assert(max_message.bytes().get(iter_2).unwrap() == 255u8);
+ iter_2 += 1;
+ }
+
+ let other_message = Message::from(other_b256);
+ assert(other_message.bytes().len() == 32);
+ assert(other_message.bytes().get(31).unwrap() == 1u8);
+ let mut iter_3 = 0;
+ while iter_3 < other_message.bytes().len() - 1 {
+ assert(other_message.bytes().get(iter_3).unwrap() == 0u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn message_from_bytes() {
+ let mut bytes_1 = Bytes::new();
+ bytes_1.push(1u8);
+ bytes_1.push(3u8);
+ bytes_1.push(5u8);
+ let message_1 = Message::from(bytes_1);
+ assert(message_1.bytes().len() == 3);
+ assert(message_1.bytes().get(0).unwrap() == 1u8);
+ assert(message_1.bytes().get(1).unwrap() == 3u8);
+ assert(message_1.bytes().get(2).unwrap() == 5u8);
+
+ let mut bytes_2 = Bytes::new();
+ bytes_2.push(1u8);
+ bytes_2.push(3u8);
+ bytes_2.push(5u8);
+ bytes_2.push(9u8);
+ bytes_2.push(11u8);
+ bytes_2.push(13u8);
+ let message_2 = Message::from(bytes_2);
+ assert(message_2.bytes().len() == 6);
+ assert(message_2.bytes().get(0).unwrap() == 1u8);
+ assert(message_2.bytes().get(1).unwrap() == 3u8);
+ assert(message_2.bytes().get(2).unwrap() == 5u8);
+ assert(message_2.bytes().get(3).unwrap() == 9u8);
+ assert(message_2.bytes().get(4).unwrap() == 11u8);
+ assert(message_2.bytes().get(5).unwrap() == 13u8);
+
+ let mut bytes_3 = Bytes::new();
+ bytes_3.push(0u8);
+ let message_3 = Message::from(bytes_3);
+ assert(message_3.bytes().len() == 1);
+ assert(message_3.bytes().get(0).unwrap() == 0u8);
+
+ let mut bytes_4 = Bytes::new();
+ let message_4 = Message::from(bytes_4);
+ assert(message_4.bytes().len() == 0);
+ assert(message_4.bytes().get(0).is_none());
+}
+
+#[test]
+fn message_try_into_b256() {
+ let zero_b256 = b256::zero();
+ let max_b256 = b256::max();
+ let other_b256 = 0x0000000000000000000000000000000000000000000000000000000000000001;
+ let mut bytes = Bytes::from(b256::max());
+ bytes.push(0u8);
+
+ let zero_message = Message::from(zero_b256);
+ let b256_1 = >::try_into(zero_message);
+ assert(b256_1.unwrap() == zero_b256);
+
+ let max_message = Message::from(max_b256);
+ let b256_2 = >::try_into(max_message);
+ assert(b256_2.unwrap() == max_b256);
+
+ let other_message = Message::from(other_b256);
+ let b256_3 = >::try_into(other_message);
+ assert(b256_3.unwrap() == other_b256);
+
+ let bytes_message = Message::from(bytes);
+ let b256_4 = >::try_into(bytes_message);
+ assert(b256_4.is_none());
+}
+
+#[test]
+fn message_eq() {
+ let zero_b256 = b256::zero();
+ let max_b256 = b256::max();
+ let other_b256 = 0x0000000000000000000000000000000000000000000000000000000000000001;
+ let mut bytes_1 = Bytes::new();
+ bytes_1.push(1u8);
+ bytes_1.push(3u8);
+ bytes_1.push(5u8);
+ let mut bytes_2 = Bytes::new();
+ bytes_2.push(1u8);
+ bytes_2.push(3u8);
+ bytes_2.push(5u8);
+ bytes_2.push(9u8);
+ bytes_2.push(11u8);
+ bytes_2.push(13u8);
+ let mut bytes_3 = Bytes::new();
+ bytes_3.push(0u8);
+ let mut bytes_4 = Bytes::new();
+
+ let zero_message_1 = Message::from(zero_b256);
+ let zero_message_2 = Message::from(zero_b256);
+ let max_message_1 = Message::from(max_b256);
+ let max_message_2 = Message::from(max_b256);
+ let other_message_1 = Message::from(other_b256);
+ let other_message_2 = Message::from(other_b256);
+ let message_bytes_1_1 = Message::from(bytes_1);
+ let message_bytes_1_2 = Message::from(bytes_1);
+ let message_bytes_2_1 = Message::from(bytes_2);
+ let message_bytes_2_2 = Message::from(bytes_2);
+ let message_bytes_3_1 = Message::from(bytes_3);
+ let message_bytes_3_2 = Message::from(bytes_3);
+ let message_bytes_4_1 = Message::from(bytes_4);
+ let message_bytes_4_2 = Message::from(bytes_4);
+
+ assert(zero_message_1 == zero_message_2);
+ assert(max_message_1 == max_message_2);
+ assert(other_message_1 == other_message_2);
+ assert(message_bytes_1_1 == message_bytes_1_2);
+ assert(message_bytes_2_1 == message_bytes_2_2);
+ assert(message_bytes_3_1 == message_bytes_3_2);
+ assert(message_bytes_4_1 == message_bytes_4_2);
+
+ assert(zero_message_1 != max_message_1);
+ assert(zero_message_1 != other_message_1);
+ assert(zero_message_1 != message_bytes_1_1);
+ assert(zero_message_1 != message_bytes_2_1);
+ assert(zero_message_1 != message_bytes_3_1);
+ assert(zero_message_1 != message_bytes_4_1);
+
+ assert(max_message_1 != other_message_1);
+ assert(max_message_1 != message_bytes_1_1);
+ assert(max_message_1 != message_bytes_2_1);
+ assert(max_message_1 != message_bytes_3_1);
+ assert(max_message_1 != message_bytes_4_1);
+
+ assert(other_message_1 != message_bytes_1_1);
+ assert(other_message_1 != message_bytes_2_1);
+ assert(other_message_1 != message_bytes_3_1);
+ assert(other_message_1 != message_bytes_4_1);
+
+ assert(message_bytes_1_1 != message_bytes_2_1);
+ assert(message_bytes_1_1 != message_bytes_3_1);
+ assert(message_bytes_1_1 != message_bytes_4_1);
+
+ assert(message_bytes_2_1 != message_bytes_3_1);
+ assert(message_bytes_2_1 != message_bytes_4_1);
+
+ assert(message_bytes_3_1 != message_bytes_4_1);
+}
+
+#[test]
+fn message_hash() {
+ let zero_message = Message::from(b256::zero());
+ let result_1 = sha256(zero_message);
+ assert(result_1 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925);
+
+ let one_message = Message::from(0x0000000000000000000000000000000000000000000000000000000000000001);
+ let result_2 = sha256(one_message);
+ assert(result_2 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5);
+}
diff --git a/test/src/in_language_tests/test_programs/crypto_public_key_inline_tests/Forc.toml b/test/src/in_language_tests/test_programs/crypto_public_key_inline_tests/Forc.toml
new file mode 100644
index 00000000000..ebc31cac8e2
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_public_key_inline_tests/Forc.toml
@@ -0,0 +1,8 @@
+[project]
+authors = ["Fuel Labs "]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "crypto_public_key_inline_tests"
+
+[dependencies]
+std = { path = "../../../../../sway-lib-std" }
diff --git a/test/src/in_language_tests/test_programs/crypto_public_key_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/crypto_public_key_inline_tests/src/main.sw
new file mode 100644
index 00000000000..4920a726ca6
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_public_key_inline_tests/src/main.sw
@@ -0,0 +1,312 @@
+library;
+
+use std::{b512::B512, bytes::Bytes, crypto::public_key::*, hash::{Hash, sha256}};
+
+#[test]
+fn public_key_new() {
+ let new_public_key = PublicKey::new();
+
+ assert(new_public_key.bytes().len() == 0);
+ assert(new_public_key.bytes().capacity() == 0);
+}
+
+#[test]
+fn public_key_bytes() {
+ let new_public_key = PublicKey::new();
+ let new_public_key_bytes = new_public_key.bytes();
+ assert(new_public_key_bytes.len() == 0);
+ assert(new_public_key_bytes.capacity() == 0);
+
+ let other_public_key = PublicKey::from(b256::max());
+ let other_public_key_bytes = other_public_key.bytes();
+ assert(other_public_key_bytes.len() == 32);
+ assert(other_public_key_bytes.get(0).unwrap() == 255u8);
+ assert(other_public_key_bytes.get(1).unwrap() == 255u8);
+ assert(other_public_key_bytes.get(2).unwrap() == 255u8);
+}
+
+#[test]
+fn public_key_is_zero() {
+ let new_public_key = PublicKey::new();
+ assert(new_public_key.is_zero());
+
+ let b256_public_key = PublicKey::from(b256::zero());
+ assert(b256_public_key.is_zero());
+
+ let b256_tuple_public_key = PublicKey::from((b256::zero(), b256::zero()));
+ assert(b256_tuple_public_key.is_zero());
+}
+
+#[test]
+fn public_key_from_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let public_key_1 = PublicKey::from(b512_1);
+ assert(public_key_1.bytes().len() == 64);
+ let mut iter_1 = 0;
+ while iter_1 < public_key_1.bytes().len() {
+ assert(public_key_1.bytes().get(iter_1).unwrap() == 0u8);
+ iter_1 += 1;
+ }
+
+ let b512_2 = B512::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let public_key_2 = PublicKey::from(b512_2);
+ assert(public_key_2.bytes().len() == 64);
+ assert(public_key_2.bytes().get(63).unwrap() == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < public_key_2.bytes().len() - 1{
+ assert(public_key_2.bytes().get(iter_2).unwrap() == 0u8);
+ iter_2 += 1;
+ }
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let public_key_3 = PublicKey::from(b512_3);
+ assert(public_key_3.bytes().len() == 64);
+ let mut iter_3 = 0;
+ while iter_3 < public_key_3.bytes().len() {
+ assert(public_key_3.bytes().get(iter_3).unwrap() == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn public_key_from_b256_tuple() {
+ let public_key_1 = PublicKey::from((b256::zero(), b256::zero()));
+ assert(public_key_1.bytes().len() == 64);
+ let mut iter_1 = 0;
+ while iter_1 < public_key_1.bytes().len() {
+ assert(public_key_1.bytes().get(iter_1).unwrap() == 0u8);
+ iter_1 += 1;
+ }
+
+ let public_key_2 = PublicKey::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ assert(public_key_2.bytes().len() == 64);
+ assert(public_key_2.bytes().get(63).unwrap() == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < public_key_2.bytes().len() - 1{
+ assert(public_key_2.bytes().get(iter_2).unwrap() == 0u8);
+ iter_2 += 1;
+ }
+
+ let public_key_3 = PublicKey::from((b256::max(), b256::max()));
+ assert(public_key_3.bytes().len() == 64);
+ let mut iter_3 = 0;
+ while iter_3 < public_key_3.bytes().len() {
+ assert(public_key_3.bytes().get(iter_3).unwrap() == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn public_key_from_b256() {
+ let public_key_1 = PublicKey::from(b256::zero());
+ assert(public_key_1.bytes().len() == 32);
+ let mut iter_1 = 0;
+ while iter_1 < public_key_1.bytes().len() {
+ assert(public_key_1.bytes().get(iter_1).unwrap() == 0u8);
+ iter_1 += 1;
+ }
+
+ let public_key_2 = PublicKey::from(0x0000000000000000000000000000000000000000000000000000000000000001);
+ assert(public_key_2.bytes().len() == 32);
+ assert(public_key_2.bytes().get(31).unwrap() == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < public_key_2.bytes().len() - 1{
+ assert(public_key_2.bytes().get(iter_2).unwrap() == 0u8);
+ iter_2 += 1;
+ }
+
+ let public_key_3 = PublicKey::from(b256::max());
+ assert(public_key_3.bytes().len() == 32);
+ let mut iter_3 = 0;
+ while iter_3 < public_key_3.bytes().len() {
+ assert(public_key_3.bytes().get(iter_3).unwrap() == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn public_key_try_from_bytes() {
+ let mut bytes_1 = Bytes::new();
+ let public_key_1 = PublicKey::try_from(bytes_1);
+ assert(public_key_1.is_none());
+
+ let mut bytes_2 = Bytes::new();
+ bytes_2.push(1u8);
+ bytes_2.push(2u8);
+ bytes_2.push(3u8);
+ let public_key_2 = PublicKey::try_from(bytes_2);
+ assert(public_key_2.is_none());
+
+ let bytes_3 = Bytes::from(b256::zero());
+ let public_key_3 = PublicKey::try_from(bytes_3).unwrap();
+ assert(public_key_3.bytes().len() == 32);
+ let mut iter_3 = 0;
+ while iter_3 < public_key_3.bytes().len() {
+ assert(public_key_3.bytes().get(iter_3).unwrap() == 0u8);
+ iter_3 += 1;
+ }
+
+ let bytes_4 = Bytes::from(b256::max());
+ let public_key_4 = PublicKey::try_from(bytes_4).unwrap();
+ assert(public_key_4.bytes().len() == 32);
+ let mut iter_4 = 0;
+ while iter_4 < public_key_4.bytes().len() {
+ assert(public_key_4.bytes().get(iter_4).unwrap() == 255u8);
+ iter_4 += 1;
+ }
+
+ let bytes_5 = Bytes::from(0x0000000000000000000000000000000000000000000000000000000000000001);
+ let public_key_5 = PublicKey::try_from(bytes_5).unwrap();
+ assert(public_key_5.bytes().len() == 32);
+ assert(public_key_5.bytes().get(31).unwrap() == 1u8);
+ let mut iter_5 = 0;
+ while iter_5 < public_key_5.bytes().len() - 1 {
+ assert(public_key_5.bytes().get(iter_5).unwrap() == 0u8);
+ iter_5 += 1;
+ }
+
+ let b256_tuple_6 = (b256::zero(), b256::zero());
+ let bytes_6 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_6), 64));
+ let public_key_6 = PublicKey::try_from(bytes_6).unwrap();
+ assert(public_key_6.bytes().len() == 64);
+ let mut iter_6 = 0;
+ while iter_6 < public_key_6.bytes().len() {
+ assert(public_key_6.bytes().get(iter_6).unwrap() == 0u8);
+ iter_6 += 1;
+ }
+
+ let b256_tuple_7 = (b256::max(), b256::max());
+ let bytes_7 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_7), 64));
+ let public_key_7 = PublicKey::try_from(bytes_7).unwrap();
+ assert(public_key_7.bytes().len() == 64);
+ let mut iter_7 = 0;
+ while iter_7 < public_key_7.bytes().len() {
+ assert(public_key_7.bytes().get(iter_7).unwrap() == 255u8);
+ iter_7 += 1;
+ }
+
+ let b256_tuple_8 = (b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001);
+ let bytes_8 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_8), 64));
+ let public_key_8 = PublicKey::try_from(bytes_8).unwrap();
+ assert(public_key_8.bytes().len() == 64);
+ assert(public_key_8.bytes().get(63).unwrap() == 1u8);
+ let mut iter_8 = 0;
+ while iter_8 < public_key_8.bytes().len() - 1 {
+ assert(public_key_8.bytes().get(iter_8).unwrap() == 0u8);
+ iter_8 += 1;
+ }
+}
+
+#[test]
+fn public_key_try_into_b256_tuple() {
+ let public_key_1 = PublicKey::from((b256::zero(), b256::zero()));
+ let (result_1_1, result_2_1) = >::try_into(public_key_1).unwrap();
+ assert(result_1_1 == b256::zero());
+ assert(result_2_1 == b256::zero());
+
+ let public_key_2 = PublicKey::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let (result_1_2, result_2_2) = >::try_into(public_key_2).unwrap();
+ assert(result_1_2 == b256::zero());
+ assert(result_2_2 == 0x0000000000000000000000000000000000000000000000000000000000000001);
+
+ let public_key_3 = PublicKey::from((b256::max(), b256::max()));
+ let (result_1_3, result_2_3) = >::try_into(public_key_3).unwrap();
+ assert(result_1_3 == b256::max());
+ assert(result_2_3 == b256::max());
+
+ let public_key_4 = PublicKey::from(b256::zero());
+ let result_4 = >::try_into(public_key_4);
+ assert(result_4.is_none());
+}
+
+#[test]
+fn public_key_try_into_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let public_key_1 = PublicKey::from(b512_1);
+ assert(>::try_into(public_key_1).unwrap() == b512_1);
+
+ let b512_2 = B512::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let public_key_2 = PublicKey::from(b512_2);
+ assert(>::try_into(public_key_2).unwrap() == b512_2);
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let public_key_3 = PublicKey::from(b512_3);
+ assert(>::try_into(public_key_3).unwrap() == b512_3);
+
+ let public_key_4 = PublicKey::from(b256::zero());
+ let result = >::try_into(public_key_4);
+ assert(result.is_none());
+}
+
+#[test]
+fn public_key_try_into_b256() {
+ let public_key_1 = PublicKey::from(b256::zero());
+ let result_1: b256 = >::try_into(public_key_1).unwrap();
+ assert(result_1 == b256::zero());
+
+ let public_key_2 = PublicKey::from(0x0000000000000000000000000000000000000000000000000000000000000001);
+ let result_2: b256 = >::try_into(public_key_2).unwrap();
+ assert(result_2 == 0x0000000000000000000000000000000000000000000000000000000000000001);
+
+ let public_key_3 = PublicKey::from(b256::max());
+ let result_3: b256 = >::try_into(public_key_3).unwrap();
+ assert(result_3 == b256::max());
+
+ let public_key_4 = PublicKey::from((b256::zero(), b256::zero()));
+ let result_4 = >::try_into(public_key_4);
+ assert(result_4.is_none());
+}
+
+#[test]
+fn public_key_eq() {
+ let public_key_1 = PublicKey::from(b256::zero());
+ let public_key_2 = PublicKey::from(b256::zero());
+ let public_key_3 = PublicKey::from(b256::max());
+ let public_key_4 = PublicKey::from(b256::max());
+ let public_key_5 = PublicKey::from(0x0000000000000000000000000000000000000000000000000000000000000001);
+ let public_key_6 = PublicKey::from(0x0000000000000000000000000000000000000000000000000000000000000001);
+ let public_key_7 = PublicKey::from((b256::zero(), b256::zero()));
+ let public_key_8 = PublicKey::from((b256::zero(), b256::zero()));
+ let public_key_9 = PublicKey::from((b256::max(), b256::max()));
+ let public_key_10 = PublicKey::from((b256::max(), b256::max()));
+ let public_key_11 = PublicKey::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let public_key_12 = PublicKey::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+
+ assert(public_key_1 == public_key_2);
+ assert(public_key_3 == public_key_4);
+ assert(public_key_5 == public_key_6);
+ assert(public_key_7 == public_key_8);
+ assert(public_key_9 == public_key_10);
+ assert(public_key_11 == public_key_12);
+
+ assert(public_key_1 != public_key_3);
+ assert(public_key_1 != public_key_5);
+ assert(public_key_1 != public_key_7);
+ assert(public_key_1 != public_key_9);
+ assert(public_key_1 != public_key_11);
+
+ assert(public_key_3 != public_key_5);
+ assert(public_key_3 != public_key_7);
+ assert(public_key_3 != public_key_9);
+ assert(public_key_3 != public_key_11);
+
+ assert(public_key_5 != public_key_7);
+ assert(public_key_5 != public_key_9);
+ assert(public_key_5 != public_key_11);
+
+ assert(public_key_7 != public_key_9);
+ assert(public_key_7 != public_key_11);
+
+ assert(public_key_9 != public_key_11);
+}
+
+#[test]
+fn public_key_hash() {
+ let zero_public_key = PublicKey::from(b256::zero());
+ let result_1 = sha256(zero_public_key);
+ assert(result_1 == 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925);
+
+ let one_public_key = PublicKey::from(0x0000000000000000000000000000000000000000000000000000000000000001);
+ let result_2 = sha256(one_public_key);
+ assert(result_2 == 0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5);
+}
diff --git a/test/src/in_language_tests/test_programs/crypto_secp256k1_inline_tests/Forc.toml b/test/src/in_language_tests/test_programs/crypto_secp256k1_inline_tests/Forc.toml
new file mode 100644
index 00000000000..e8fe0b5f9f1
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_secp256k1_inline_tests/Forc.toml
@@ -0,0 +1,8 @@
+[project]
+authors = ["Fuel Labs "]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "crypto_secp256k1_inline_tests"
+
+[dependencies]
+std = { path = "../../../../../sway-lib-std" }
diff --git a/test/src/in_language_tests/test_programs/crypto_secp256k1_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/crypto_secp256k1_inline_tests/src/main.sw
new file mode 100644
index 00000000000..4473eff8d61
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_secp256k1_inline_tests/src/main.sw
@@ -0,0 +1,454 @@
+library;
+
+use std::{
+ b512::B512,
+ bytes::Bytes,
+ crypto::{
+ message::*,
+ public_key::*,
+ secp256k1::*,
+ },
+ hash::{
+ Hash,
+ sha256,
+ },
+ vm::evm::evm_address::EvmAddress,
+};
+
+#[test]
+fn secp256k1_new() {
+ let new_secp256k1 = Secp256k1::new();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(new_secp256k1.bits()[iter] == 0u8);
+ iter += 1;
+ }
+}
+
+#[test]
+fn secp256k1_bits() {
+ let new_secp256k1 = Secp256k1::new();
+ let secp256k1_bits = new_secp256k1.bits();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(secp256k1_bits[iter] == 0u8);
+ iter += 1;
+ }
+}
+
+#[test]
+fn secp256k1_recover() {
+ let hi = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let pub_hi = 0x41a55558a3486b6ee3878f55f16879c0798afd772c1506de44aba90d29b6e65c;
+ let pub_lo = 0x341ca2e0a3d5827e78d838e35b29bebe2a39ac30b58999e1138c9467bf859965;
+ let signature: Secp256k1 = Secp256k1::from((hi, lo));
+ let public_key = PublicKey::from((pub_hi, pub_lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered public key pair.
+ let result_public_key = signature.recover(message);
+ assert(result_public_key.is_ok());
+ assert(public_key == result_public_key.unwrap());
+
+ let hi_2 = b256::zero();
+ let lo_2 = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash_2 = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let signature_2 = Secp256k1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.recover(message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256k1_address() {
+ let hi = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let address = Address::from(0x02844f00cce0f608fa3f0f7408bec96bfd757891a6fda6e1fa0f510398304881);
+ let signature = Secp256k1::from((hi, lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered Fuel address.
+ let result_address = signature.address(message);
+ assert(result_address.is_ok());
+ assert(result_address.unwrap() == address);
+
+ let hi_2 = b256::zero();
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let signature_2 = Secp256k1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.address(message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256k1_evm_address() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_1 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let expected_evm_address = EvmAddress::from(0x0000000000000000000000000ec44cf95ce5051ef590e6d420f8e722dd160ecb);
+ let signature_1 = Secp256k1::from((hi_1, lo_1));
+ let message_1 = Message::from(msg_hash_1);
+
+ let result_1 = signature_1.evm_address(message_1);
+ assert(result_1.is_ok());
+ assert(result_1.unwrap() == expected_evm_address);
+
+ let hi_2 = 0xbd0c9b8792876713afa8bf1383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_2 = 0xee45573606c96c98ba170ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52cad30b89df1e4a9c4323;
+ let signature_2 = Secp256k1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.evm_address(message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256k1_verify() {
+ let hi = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let pub_hi = 0x41a55558a3486b6ee3878f55f16879c0798afd772c1506de44aba90d29b6e65c;
+ let pub_lo = 0x341ca2e0a3d5827e78d838e35b29bebe2a39ac30b58999e1138c9467bf859965;
+ let signature = Secp256k1::from((hi, lo));
+ let public_key = PublicKey::from((pub_hi, pub_lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered public key pair.
+ let result = signature.verify(public_key, message);
+ assert(result.is_ok());
+
+ let hi_2 = b256::zero();
+ let lo_2 = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash_2 = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let pub_hi_2 = 0x41a55558a3486b6ee3878f55f16879c0798afd772c1506de44aba90d29b6e65c;
+ let pub_lo_2 = 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452;
+ let signature_2 = Secp256k1::from((hi_2, lo_2));
+ let public_key_2 = PublicKey::from((pub_hi_2, pub_lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.verify(public_key_2, message_2);
+ assert(result_2.is_err());
+
+ let hi_3 = 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac;
+ let lo_3 = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash_3 = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let pub_3 = b256::zero();
+ let signature_3 = Secp256k1::from((hi_3, lo_3));
+ let public_key_3 = PublicKey::from(pub_3);
+ let message_3 = Message::from(msg_hash_3);
+
+ let result_3 = signature_3.verify(public_key_3, message_3);
+ assert(result_3.is_err());
+}
+
+#[test]
+fn secp256k1_verify_address() {
+ let hi = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let address = Address::from(0x02844f00cce0f608fa3f0f7408bec96bfd757891a6fda6e1fa0f510398304881);
+ let signature = Secp256k1::from((hi, lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered Fuel address.
+ let result = signature.verify_address(address, message);
+ assert(result.is_ok());
+
+ let hi_2 = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo_2 = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash_2 = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let address_2 = Address::zero();
+ let signature_2 = Secp256k1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered Fuel address.
+ let result_2 = signature.verify_address(address_2, message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256k1_verify_evm_address() {
+ let hi = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address = EvmAddress::from(0x0000000000000000000000000ec44cf95ce5051ef590e6d420f8e722dd160ecb);
+ let signature = Secp256k1::from((hi, lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered EVM address.
+ let result = signature.verify_evm_address(address, message);
+ assert(result.is_ok());
+
+ let hi_2 = 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address_2 = EvmAddress::zero();
+ let signature_2 = Secp256k1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered Fuel address.
+ let result_2 = signature.verify_evm_address(address_2, message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256k1_from_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let secp256k1_1 = Secp256k1::from(b512_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256k1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let b512_2 = B512::from((
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ ));
+ let secp256k1_2 = Secp256k1::from(b512_2);
+ assert(secp256k1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256k1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let secp256k1_3 = Secp256k1::from(b512_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256k1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256k1_from_b256_tuple() {
+ let secp256k1_1 = Secp256k1::from((b256::zero(), b256::zero()));
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256k1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let secp256k1_2 = Secp256k1::from((
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ ));
+ assert(secp256k1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256k1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let secp256k1_3 = Secp256k1::from((b256::max(), b256::max()));
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256k1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256k1_from_u8_array() {
+ let array_1 = [
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8,
+ ];
+ let secp256k1_1 = Secp256k1::from(array_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256k1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let array_2 = [
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 1u8,
+ ];
+ let secp256k1_2 = Secp256k1::from(array_2);
+ assert(secp256k1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256k1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let array_3 = [
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ ];
+ let secp256k1_3 = Secp256k1::from(array_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256k1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256k1_try_from_bytes() {
+ let b256_tuple_1 = (b256::zero(), b256::zero());
+ let bytes_1 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_1), 64));
+ let secp256k1_1 = Secp256k1::try_from(bytes_1).unwrap();
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256k1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let b256_tuple_2 = (
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ );
+ let bytes_2 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_2), 64));
+ let secp256k1_2 = Secp256k1::try_from(bytes_2).unwrap();
+ assert(secp256k1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256k1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let b256_tuple_3 = (b256::max(), b256::max());
+ let bytes_3 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_3), 64));
+ let secp256k1_3 = Secp256k1::try_from(bytes_3).unwrap();
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256k1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+
+ let bytes_4 = Bytes::new();
+ let secp256k1_4 = Secp256k1::try_from(bytes_4);
+ assert(secp256k1_4.is_none());
+
+ let mut bytes_5 = Bytes::new();
+ bytes_5.push(0u8);
+ bytes_5.push(0u8);
+ bytes_5.push(0u8);
+ let secp256k1_5 = Secp256k1::try_from(bytes_5);
+ assert(secp256k1_5.is_none());
+}
+
+#[test]
+fn secp256k1_into_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let secp256k1_1 = Secp256k1::from(b512_1);
+ assert(>::into(secp256k1_1) == b512_1);
+
+ let b512_2 = B512::from((
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ ));
+ let secp256k1_2 = Secp256k1::from(b512_2);
+ assert(>::into(secp256k1_2) == b512_2);
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let secp256k1_3 = Secp256k1::from(b512_3);
+ assert(>::into(secp256k1_3) == b512_3);
+}
+
+#[test]
+fn secp256k1_into_b256_tuple() {
+ let secp256k1_1 = Secp256k1::from((b256::zero(), b256::zero()));
+ let (result_1_1, result_2_1) = >::into(secp256k1_1);
+ assert(result_1_1 == b256::zero());
+ assert(result_2_1 == b256::zero());
+
+ let secp256k1_2 = Secp256k1::from((
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ ));
+ let (result_1_2, result_2_2) = >::into(secp256k1_2);
+ assert(result_1_2 == b256::zero());
+ assert(
+ result_2_2 == 0x0000000000000000000000000000000000000000000000000000000000000001,
+ );
+
+ let secp256k1_3 = Secp256k1::from((b256::max(), b256::max()));
+ let (result_1_3, result_2_3) = >::into(secp256k1_3);
+ assert(result_1_3 == b256::max());
+ assert(result_2_3 == b256::max());
+}
+
+#[test]
+fn secp256k1_into_bytes() {
+ let secp256k1_1 = Secp256k1::from((b256::zero(), b256::zero()));
+ let bytes_result_1 = >::into(secp256k1_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(bytes_result_1.get(iter_1).unwrap() == 0u8);
+ iter_1 += 1;
+ }
+
+ let secp256k1_2 = Secp256k1::from((
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ ));
+ let bytes_result_2 = >::into(secp256k1_2);
+ assert(bytes_result_2.get(63).unwrap() == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(bytes_result_2.get(iter_2).unwrap() == 0u8);
+ iter_2 += 1;
+ }
+
+ let secp256k1_3 = Secp256k1::from((b256::max(), b256::max()));
+ let bytes_result_3 = >::into(secp256k1_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(bytes_result_3.get(iter_3).unwrap() == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256k1_eq() {
+ let secp256k1_1 = Secp256k1::from((b256::zero(), b256::zero()));
+ let secp256k1_2 = Secp256k1::from((b256::zero(), b256::zero()));
+ let secp256k1_3 = Secp256k1::from((
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ ));
+ let secp256k1_4 = Secp256k1::from((
+ b256::zero(),
+ 0x0000000000000000000000000000000000000000000000000000000000000001,
+ ));
+ let secp256k1_5 = Secp256k1::from((b256::max(), b256::max()));
+ let secp256k1_6 = Secp256k1::from((b256::max(), b256::max()));
+
+ assert(secp256k1_1 == secp256k1_2);
+ assert(secp256k1_3 == secp256k1_4);
+ assert(secp256k1_5 == secp256k1_6);
+
+ assert(secp256k1_1 != secp256k1_3);
+ assert(secp256k1_1 != secp256k1_5);
+
+ assert(secp256k1_3 != secp256k1_5);
+}
+
+#[test]
+fn secp256k1_hash() {
+ let secp256k1 = Secp256k1::from((b256::zero(), b256::zero()));
+ let hash = sha256(secp256k1);
+ assert(hash == 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b);
+}
diff --git a/test/src/in_language_tests/test_programs/crypto_secp256r1_inline_tests/Forc.toml b/test/src/in_language_tests/test_programs/crypto_secp256r1_inline_tests/Forc.toml
new file mode 100644
index 00000000000..728ad627600
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_secp256r1_inline_tests/Forc.toml
@@ -0,0 +1,8 @@
+[project]
+authors = ["Fuel Labs "]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "crypto_secp256r1_inline_tests"
+
+[dependencies]
+std = { path = "../../../../../sway-lib-std" }
diff --git a/test/src/in_language_tests/test_programs/crypto_secp256r1_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/crypto_secp256r1_inline_tests/src/main.sw
new file mode 100644
index 00000000000..f8feda0bea0
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_secp256r1_inline_tests/src/main.sw
@@ -0,0 +1,414 @@
+library;
+
+use std::{b512::B512, bytes::Bytes, crypto::{secp256r1::*, public_key::*, message::*}, hash::{Hash, sha256}, vm::evm::evm_address::EvmAddress};
+
+#[test]
+fn secp256r1_new() {
+ let new_secp256r1 = Secp256r1::new();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(new_secp256r1.bits()[iter] == 0u8);
+ iter += 1;
+ }
+}
+
+#[test]
+fn secp256r1_bits() {
+ let new_secp256r1 = Secp256r1::new();
+ let secp256r1_bits = new_secp256r1.bits();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(secp256r1_bits[iter] == 0u8);
+ iter += 1;
+ }
+}
+
+#[test]
+fn secp256r1_recover() {
+ let hi = 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac;
+ let lo = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let pub_hi = 0xd6ea577a54ae42411fbc78d686d4abba2150ca83540528e4b868002e346004b2;
+ let pub_lo = 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452;
+ let signature: Secp256r1 = Secp256r1::from((hi, lo));
+ let public_key = PublicKey::from((pub_hi, pub_lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered public key pair.
+ let result_public_key = signature.recover(message);
+ assert(result_public_key.is_ok());
+ assert(public_key == result_public_key.unwrap());
+
+ let hi_2 = b256::zero();
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash_2 = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let signature_2 = Secp256r1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.recover(message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256r1_address() {
+ let hi = 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address = Address::from(0xb4a5fabee8cc852084b71f17107e9c18d682033a58967027af0ab01edf2f9a6a);
+ let signature = Secp256r1::from((hi, lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered Fuel address.
+ let result_address = signature.address(message);
+ assert(result_address.is_ok());
+ assert(result_address.unwrap() == address);
+
+ let hi_2 = b256::zero();
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let signature_2 = Secp256r1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.address(message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256r1_evm_address() {
+ let hi_1 = 0x62CDC20C0AB6AA7B91E63DA9917792473F55A6F15006BC99DD4E29420084A3CC;
+ let lo_1 = 0xF4D99AF28F9D6BD96BDAAB83BFED99212AC3C7D06810E33FBB14C4F29B635414;
+ let msg_hash_1 = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;
+ let expected_evm_address = EvmAddress::from(0x000000000000000000000000408eb2d97ef0beda0a33848d9e052066667cb00a);
+ let signature_1 = Secp256r1::from((hi_1, lo_1));
+ let message_1 = Message::from(msg_hash_1);
+
+ let result_1 = signature_1.evm_address(message_1);
+ assert(result_1.is_ok());
+ assert(result_1.unwrap() == expected_evm_address);
+
+ let hi_2 = b256::zero();
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let signature_2 = Secp256r1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.evm_address(message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256r1_verify() {
+ let hi = 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac;
+ let lo = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let pub_hi = 0xd6ea577a54ae42411fbc78d686d4abba2150ca83540528e4b868002e346004b2;
+ let pub_lo = 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452;
+ let signature = Secp256r1::from((hi, lo));
+ let public_key = PublicKey::from((pub_hi, pub_lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered public key pair.
+ let result = signature.verify(public_key, message);
+ assert(result.is_ok());
+
+ let hi_2 = 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac;
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash_2 = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let pub_hi_2 = b256::zero();
+ let pub_lo_2 = 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452;
+ let signature_2 = Secp256r1::from((hi_2, lo_2));
+ let public_key_2 = PublicKey::from((pub_hi_2, pub_lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.verify(public_key_2, message_2);
+ assert(result_2.is_err());
+
+ let hi_3 = 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac;
+ let lo_3 = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash_3 = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let pub_3 = b256::zero();
+ let signature_3 = Secp256r1::from((hi_3, lo_3));
+ let public_key_3 = PublicKey::from(pub_3);
+ let message_3 = Message::from(msg_hash_3);
+
+ let result_3 = signature_3.verify(public_key_3, message_3);
+ assert(result_3.is_err());
+}
+
+#[test]
+fn secp256r1_verify_address() {
+ let hi = 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address = Address::from(0xb4a5fabee8cc852084b71f17107e9c18d682033a58967027af0ab01edf2f9a6a);
+ let signature = Secp256r1::from((hi, lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered Fuel address.
+ let result = signature.verify_address(address, message);
+ assert(result.is_ok());
+
+ let hi_2 = 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address_2 = Address::zero();
+ let signature_2 = Secp256r1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered Fuel address.
+ let result_2 = signature.verify_address(address_2, message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256r1_verify_evm_address() {
+ let hi = 0x62CDC20C0AB6AA7B91E63DA9917792473F55A6F15006BC99DD4E29420084A3CC;
+ let lo = 0xF4D99AF28F9D6BD96BDAAB83BFED99212AC3C7D06810E33FBB14C4F29B635414;
+ let msg_hash = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;
+ let address = EvmAddress::from(0x000000000000000000000000408eb2d97ef0beda0a33848d9e052066667cb00a);
+ let signature = Secp256r1::from((hi, lo));
+ let message = Message::from(msg_hash);
+
+ // A recovered Fuel address.
+ let result = signature.verify_evm_address(address, message);
+ assert(result.is_ok());
+
+ let hi_2 = 0x62CDC20C0AB6AA7B91E63DA9917792473F55A6F15006BC99DD4E29420084A3CC;
+ let lo_2 = 0xF4D99AF28F9D6BD96BDAAB83BFED99212AC3C7D06810E33FBB14C4F29B635414;
+ let msg_hash_2 = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;
+ let address_2 = EvmAddress::zero();
+ let signature_2 = Secp256r1::from((hi_2, lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered Fuel address.
+ let result_2 = signature_2.verify_evm_address(address_2, message_2);
+ assert(result_2.is_err());
+}
+
+#[test]
+fn secp256r1_from_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let secp256r1_1 = Secp256r1::from(b512_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256r1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let b512_2 = B512::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let secp256r1_2 = Secp256r1::from(b512_2);
+ assert(secp256r1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256r1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let secp256r1_3 = Secp256r1::from(b512_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256r1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256r1_from_b256_tuple() {
+ let secp256r1_1 = Secp256r1::from((b256::zero(), b256::zero()));
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256r1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let secp256r1_2 = Secp256r1::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ assert(secp256r1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256r1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let secp256r1_3 = Secp256r1::from((b256::max(), b256::max()));
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256r1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256r1_from_u8_array() {
+ let array_1 = [
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ ];
+ let secp256r1_1 = Secp256r1::from(array_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256r1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let array_2 = [
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
+ 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
+ ];
+ let secp256r1_2 = Secp256r1::from(array_2);
+ assert(secp256r1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256r1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let array_3 = [
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8,
+ ];
+ let secp256r1_3 = Secp256r1::from(array_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256r1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256r1_try_from_bytes() {
+ let b256_tuple_1 = (b256::zero(), b256::zero());
+ let bytes_1 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_1), 64));
+ let secp256r1_1 = Secp256r1::try_from(bytes_1).unwrap();
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(secp256r1_1.bits()[iter_1] == 0u8);
+ iter_1 += 1;
+ }
+
+ let b256_tuple_2 = (b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001);
+ let bytes_2 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_2), 64));
+ let secp256r1_2 = Secp256r1::try_from(bytes_2).unwrap();
+ assert(secp256r1_2.bits()[63] == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(secp256r1_2.bits()[iter_2] == 0u8);
+ iter_2 += 1;
+ }
+
+ let b256_tuple_3 = (b256::max(), b256::max());
+ let bytes_3 = Bytes::from(raw_slice::from_parts::(__addr_of(b256_tuple_3), 64));
+ let secp256r1_3 = Secp256r1::try_from(bytes_3).unwrap();
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(secp256r1_3.bits()[iter_3] == 255u8);
+ iter_3 += 1;
+ }
+
+ let bytes_4 = Bytes::new();
+ let secp256r1_4 = Secp256r1::try_from(bytes_4);
+ assert(secp256r1_4.is_none());
+
+ let mut bytes_5 = Bytes::new();
+ bytes_5.push(0u8);
+ bytes_5.push(0u8);
+ bytes_5.push(0u8);
+ let secp256r1_5 = Secp256r1::try_from(bytes_5);
+ assert(secp256r1_5.is_none());
+}
+
+#[test]
+fn secp256r1_into_b512() {
+ let b512_1 = B512::from((b256::zero(), b256::zero()));
+ let secp256r1_1 = Secp256r1::from(b512_1);
+ assert(>::into(secp256r1_1) == b512_1);
+
+ let b512_2 = B512::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let secp256r1_2 = Secp256r1::from(b512_2);
+ assert(>::into(secp256r1_2) == b512_2);
+
+ let b512_3 = B512::from((b256::max(), b256::max()));
+ let secp256r1_3 = Secp256r1::from(b512_3);
+ assert(>::into(secp256r1_3) == b512_3);
+}
+
+#[test]
+fn secp256r1_into_b256_tuple() {
+ let secp256r1_1 = Secp256r1::from((b256::zero(), b256::zero()));
+ let (result_1_1, result_2_1) = >::into(secp256r1_1);
+ assert(result_1_1 == b256::zero());
+ assert(result_2_1 == b256::zero());
+
+ let secp256r1_2 = Secp256r1::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let (result_1_2, result_2_2) = >::into(secp256r1_2);
+ assert(result_1_2 == b256::zero());
+ assert(result_2_2 == 0x0000000000000000000000000000000000000000000000000000000000000001);
+
+ let secp256r1_3 = Secp256r1::from((b256::max(), b256::max()));
+ let (result_1_3, result_2_3) = >::into(secp256r1_3);
+ assert(result_1_3 == b256::max());
+ assert(result_2_3 == b256::max());
+}
+
+#[test]
+fn secp256r1_into_bytes() {
+ let secp256r1_1 = Secp256r1::from((b256::zero(), b256::zero()));
+ let bytes_result_1 = >::into(secp256r1_1);
+ let mut iter_1 = 0;
+ while iter_1 < 64 {
+ assert(bytes_result_1.get(iter_1).unwrap() == 0u8);
+ iter_1 += 1;
+ }
+
+ let secp256r1_2 = Secp256r1::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let bytes_result_2 = >::into(secp256r1_2);
+ assert(bytes_result_2.get(63).unwrap() == 1u8);
+ let mut iter_2 = 0;
+ while iter_2 < 63 {
+ assert(bytes_result_2.get(iter_2).unwrap() == 0u8);
+ iter_2 += 1;
+ }
+
+ let secp256r1_3 = Secp256r1::from((b256::max(), b256::max()));
+ let bytes_result_3 = >::into(secp256r1_3);
+ let mut iter_3 = 0;
+ while iter_3 < 64 {
+ assert(bytes_result_3.get(iter_3).unwrap() == 255u8);
+ iter_3 += 1;
+ }
+}
+
+#[test]
+fn secp256r1_eq() {
+ let secp256r1_1 = Secp256r1::from((b256::zero(), b256::zero()));
+ let secp256r1_2 = Secp256r1::from((b256::zero(), b256::zero()));
+ let secp256r1_3 = Secp256r1::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let secp256r1_4 = Secp256r1::from((b256::zero(), 0x0000000000000000000000000000000000000000000000000000000000000001));
+ let secp256r1_5 = Secp256r1::from((b256::max(), b256::max()));
+ let secp256r1_6 = Secp256r1::from((b256::max(), b256::max()));
+
+ assert(secp256r1_1 == secp256r1_2);
+ assert(secp256r1_3 == secp256r1_4);
+ assert(secp256r1_5 == secp256r1_6);
+
+ assert(secp256r1_1 != secp256r1_3);
+ assert(secp256r1_1 != secp256r1_5);
+
+ assert(secp256r1_3 != secp256r1_5);
+}
+
+#[test]
+fn secp256r1_hash() {
+ let secp256r1 = Secp256r1::from((b256::zero(), b256::zero()));
+ let hash = sha256(secp256r1);
+ assert(hash == 0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b);
+}
\ No newline at end of file
diff --git a/test/src/in_language_tests/test_programs/crypto_signature_inline_tests/Forc.toml b/test/src/in_language_tests/test_programs/crypto_signature_inline_tests/Forc.toml
new file mode 100644
index 00000000000..653909c62b5
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_signature_inline_tests/Forc.toml
@@ -0,0 +1,8 @@
+[project]
+authors = ["Fuel Labs "]
+entry = "main.sw"
+license = "Apache-2.0"
+name = "crypto_signature_inline_tests"
+
+[dependencies]
+std = { path = "../../../../../sway-lib-std" }
diff --git a/test/src/in_language_tests/test_programs/crypto_signature_inline_tests/src/main.sw b/test/src/in_language_tests/test_programs/crypto_signature_inline_tests/src/main.sw
new file mode 100644
index 00000000000..19ee5fcd0ba
--- /dev/null
+++ b/test/src/in_language_tests/test_programs/crypto_signature_inline_tests/src/main.sw
@@ -0,0 +1,350 @@
+library;
+
+use std::{crypto::{signature::Signature, message::Message, public_key::PublicKey, secp256k1::Secp256k1, secp256r1::Secp256r1, ed25519::Ed25519}, hash::{Hash, sha256}, vm::evm::evm_address::EvmAddress};
+
+#[test]
+fn signature_recover() {
+ let hi_1 = 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash_1 = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let pub_hi_1 = 0xd6ea577a54ae42411fbc78d686d4abba2150ca83540528e4b868002e346004b2;
+ let pub_lo_1 = 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452;
+
+ let signature_1: Signature = Signature::Secp256r1(Secp256r1::from((hi_1, lo_1)));
+ let public_key_1: PublicKey = PublicKey::from((pub_hi_1, pub_lo_1));
+ let message_1: Message = Message::from(msg_hash_1);
+
+ // A recovered public key pair.
+ let result_public_key_1 = signature_1.recover(message_1);
+ assert(result_public_key_1.is_ok());
+ assert(public_key_1 == result_public_key_1.unwrap());
+
+ let hi_2 = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo_2 = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash_2 = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let pub_hi_2 = 0x41a55558a3486b6ee3878f55f16879c0798afd772c1506de44aba90d29b6e65c;
+ let pub_lo_2 = 0x341ca2e0a3d5827e78d838e35b29bebe2a39ac30b58999e1138c9467bf859965;
+ let signature_2: Signature = Signature::Secp256k1(Secp256k1::from((hi_2, lo_2)));
+ let public_key_2 = PublicKey::from((pub_hi_2, pub_lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered public key pair.
+ let result_public_key_2 = signature_2.recover(message_2);
+ assert(result_public_key_2.is_ok());
+ assert(public_key_2 == result_public_key_2.unwrap());
+
+ let pub_key_3 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_3 = b256::zero();
+ let msg_hash_3 = sha256(msg_3);
+ let hi_3 = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo_3 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_3: PublicKey = PublicKey::from(pub_key_3);
+ let signature_3: Signature = Signature::Ed25519(Ed25519::from((hi_3, lo_3)));
+ let message_3: Message = Message::from(msg_hash_3);
+
+ // A verified public key with signature
+ let verified_3 = signature_3.recover(message_3);
+ assert(verified_3.is_err());
+}
+
+#[test]
+fn signature_address() {
+ let hi_1 = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo_1 = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash_1 = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let address_1 = Address::from(0x02844f00cce0f608fa3f0f7408bec96bfd757891a6fda6e1fa0f510398304881);
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let message_1 = Message::from(msg_hash_1);
+
+ // A recovered Fuel address.
+ let result_address_1 = signature_1.address(message_1);
+ assert(result_address_1.is_ok());
+ assert(result_address_1.unwrap() == address_1);
+
+ let hi_2 = 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address_2 = Address::from(0xb4a5fabee8cc852084b71f17107e9c18d682033a58967027af0ab01edf2f9a6a);
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_2, lo_2)));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered Fuel address.
+ let result_address_2 = signature_2.address(message_2);
+ assert(result_address_2.is_ok());
+ assert(result_address_2.unwrap() == address_2);
+
+ let pub_key_3 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_3 = b256::zero();
+ let msg_hash_3 = sha256(msg_3);
+ let hi_3 = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo_3 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_3: PublicKey = PublicKey::from(pub_key_3);
+ let signature_3: Signature = Signature::Ed25519(Ed25519::from((hi_3, lo_3)));
+ let message_3: Message = Message::from(msg_hash_3);
+
+ // A verified public key with signature
+ let verified_3 = signature_3.address(message_3);
+ assert(verified_3.is_err());
+}
+
+#[test]
+fn signature_evm_address() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_1 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let expected_evm_address_1 = EvmAddress::from(0x0000000000000000000000000ec44cf95ce5051ef590e6d420f8e722dd160ecb);
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let message_1 = Message::from(msg_hash_1);
+
+ let result_1 = signature_1.evm_address(message_1);
+ assert(result_1.is_ok());
+ assert(result_1.unwrap() == expected_evm_address_1);
+
+ let hi_2 = 0x62CDC20C0AB6AA7B91E63DA9917792473F55A6F15006BC99DD4E29420084A3CC;
+ let lo_2 = 0xF4D99AF28F9D6BD96BDAAB83BFED99212AC3C7D06810E33FBB14C4F29B635414;
+ let msg_hash_2 = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;
+ let expected_evm_address_2 = EvmAddress::from(0x000000000000000000000000408eb2d97ef0beda0a33848d9e052066667cb00a);
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_2, lo_2)));
+ let message_2 = Message::from(msg_hash_2);
+
+ let result_2 = signature_2.evm_address(message_2);
+ assert(result_2.is_ok());
+ assert(result_2.unwrap() == expected_evm_address_2);
+
+ let pub_key_3 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_3 = b256::zero();
+ let msg_hash_3 = sha256(msg_3);
+ let hi_3 = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo_3 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_3: PublicKey = PublicKey::from(pub_key_3);
+ let signature_3: Signature = Signature::Ed25519(Ed25519::from((hi_3, lo_3)));
+ let message_3: Message = Message::from(msg_hash_3);
+
+ // A verified public key with signature
+ let verified_3 = signature_3.evm_address(message_3);
+ assert(verified_3.is_err());
+}
+
+#[test]
+fn signature_verify() {
+ let hi_1 = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo_1 = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash_1 = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let pub_hi_1 = 0x41a55558a3486b6ee3878f55f16879c0798afd772c1506de44aba90d29b6e65c;
+ let pub_lo_1 = 0x341ca2e0a3d5827e78d838e35b29bebe2a39ac30b58999e1138c9467bf859965;
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let public_key_1 = PublicKey::from((pub_hi_1, pub_lo_1));
+ let message_1 = Message::from(msg_hash_1);
+
+ // A recovered public key pair.
+ let result_1 = signature_1.verify(public_key_1, message_1);
+ assert(result_1.is_ok());
+
+ let hi_2 = 0xbd0c9b8792876712afadbff382e1bf31c44437823ed761cc3600d0016de511ac;
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3da360c695edb27dc3b64d621e122fea23d;
+ let msg_hash_2 = 0x1e45523606c96c98ba970ff7cf9511fab8b25e1bcd52ced30b81df1e4a9c4323;
+ let pub_hi_2 = 0xd6ea577a54ae42411fbc78d686d4abba2150ca83540528e4b868002e346004b2;
+ let pub_lo_2 = 0x62660ecce5979493fe5684526e8e00875b948e507a89a47096bc84064a175452;
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_2, lo_2)));
+ let public_key_2 = PublicKey::from((pub_hi_2, pub_lo_2));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered public key pair.
+ let result_2 = signature_2.verify(public_key_2, message_2);
+ assert(result_2.is_ok());
+
+ let pub_key_3 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_3 = b256::zero();
+ let msg_hash_3 = sha256(msg_3);
+ let hi_3 = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo_3 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_3: PublicKey = PublicKey::from(pub_key_3);
+ let signature_3: Signature = Signature::Ed25519(Ed25519::from((hi_3, lo_3)));
+ let message_3: Message = Message::from(msg_hash_3);
+
+ // A verified public key with signature
+ let verified_3 = signature_3.verify(public_key_3, message_3);
+ assert(verified_3.is_ok());
+}
+
+#[test]
+fn signature_verify_address() {
+ let hi_1 = 0x61f3caf4c0912cec69ff0b226638d397115c623a7f057914d48a7e4daf1cf6d8;
+ let lo_1 = 0x2555de81cd3a40382d3d64eb1c77e463eea5a76d65ec85f283e0b3d568352678;
+ let msg_hash_1 = 0xa13f4ab54057ce064d3dd97ac3ff30ed704e73956896c03650fe59b1a561fe15;
+ let address_1 = Address::from(0x02844f00cce0f608fa3f0f7408bec96bfd757891a6fda6e1fa0f510398304881);
+ let signature_1 = Secp256k1::from((hi_1, lo_1));
+ let message_1 = Message::from(msg_hash_1);
+
+ // A recovered Fuel address.
+ let result_1 = signature_1.verify_address(address_1, message_1);
+ assert(result_1.is_ok());
+
+ let hi_2 = 0xbd0c9b8792876713afa8bf3383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_2 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_2 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address_2 = Address::from(0xb4a5fabee8cc852084b71f17107e9c18d682033a58967027af0ab01edf2f9a6a);
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_2, lo_2)));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered Fuel address.
+ let result_2 = signature_2.verify_address(address_2, message_2);
+ assert(result_2.is_ok());
+
+ let pub_key_3 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_3 = b256::zero();
+ let msg_hash_3 = sha256(msg_3);
+ let hi_3 = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo_3 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_3: PublicKey = PublicKey::from(pub_key_3);
+ let signature_3: Signature = Signature::Ed25519(Ed25519::from((hi_3, lo_3)));
+ let message_3: Message = Message::from(msg_hash_3);
+
+ // A verified public key with signature
+ let verified_3 = signature_3.verify_address(address_2, message_3);
+ assert(verified_3.is_err());
+}
+
+#[test]
+fn signature_verify_evm_address() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let msg_hash_1 = 0xee45573606c96c98ba970ff7cf9511f1b8b25e6bcd52ced30b89df1e4a9c4323;
+ let address_1 = EvmAddress::from(0x0000000000000000000000000ec44cf95ce5051ef590e6d420f8e722dd160ecb);
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let message_1 = Message::from(msg_hash_1);
+
+ // A recovered Evm address.
+ let result_1 = signature_1.verify_evm_address(address_1, message_1);
+ assert(result_1.is_ok());
+
+ let hi_2 = 0x62CDC20C0AB6AA7B91E63DA9917792473F55A6F15006BC99DD4E29420084A3CC;
+ let lo_2 = 0xF4D99AF28F9D6BD96BDAAB83BFED99212AC3C7D06810E33FBB14C4F29B635414;
+ let msg_hash_2 = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563;
+ let address_2 = EvmAddress::from(0x000000000000000000000000408eb2d97ef0beda0a33848d9e052066667cb00a);
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_2, lo_2)));
+ let message_2 = Message::from(msg_hash_2);
+
+ // A recovered EVM address.
+ let result_2 = signature_2.verify_evm_address(address_2, message_2);
+ assert(result_2.is_ok());
+
+ let pub_key_3 = 0x314fa58689bbe1da2430517de2d772b384a1c1d2e9cb87e73c6afcf246045b10;
+ let msg_3 = b256::zero();
+ let msg_hash_3 = sha256(msg_3);
+ let hi_3 = 0xf38cef9361894be6c6e0eddec28a663d099d7ddff17c8077a1447d7ecb4e6545;
+ let lo_3 = 0xf5084560039486d3462dd65a40c80a74709b2f06d450ffc5dc00345c6b2cdd00;
+ let public_key_3: PublicKey = PublicKey::from(pub_key_3);
+ let signature_3: Signature = Signature::Ed25519(Ed25519::from((hi_3, lo_3)));
+ let message_3: Message = Message::from(msg_hash_3);
+
+ // A verified public key with signature
+ let verified_3 = signature_3.verify_evm_address(address_1, message_3);
+ assert(verified_3.is_err());
+}
+
+#[test]
+fn signature_as_secp256k1() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_1, lo_1)));
+ let signature_3 = Signature::Ed25519(Ed25519::from((hi_1, lo_1)));
+
+ assert(signature_1.as_secp256k1().unwrap() == Secp256k1::from((hi_1, lo_1)));
+ assert(signature_2.as_secp256k1().is_none());
+ assert(signature_3.as_secp256k1().is_none());
+}
+
+#[test]
+fn signature_as_secp256r1() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_1, lo_1)));
+ let signature_3 = Signature::Ed25519(Ed25519::from((hi_1, lo_1)));
+
+ assert(signature_1.as_secp256r1().is_none());
+ assert(signature_2.as_secp256r1().unwrap() == Secp256r1::from((hi_1, lo_1)));
+ assert(signature_3.as_secp256r1().is_none());
+}
+
+#[test]
+fn signature_as_ed25519() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_1, lo_1)));
+ let signature_3 = Signature::Ed25519(Ed25519::from((hi_1, lo_1)));
+
+ assert(signature_1.as_ed25519().is_none());
+ assert(signature_2.as_ed25519().is_none());
+ assert(signature_3.as_ed25519().unwrap() == Ed25519::from((hi_1, lo_1)));
+}
+
+#[test]
+fn signature_is_secp256k1() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_1, lo_1)));
+ let signature_3 = Signature::Ed25519(Ed25519::from((hi_1, lo_1)));
+
+ assert(signature_1.is_secp256k1());
+ assert(!signature_2.is_secp256k1());
+ assert(!signature_3.is_secp256k1());
+}
+
+#[test]
+fn signature_is_secp256r1() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_1, lo_1)));
+ let signature_3 = Signature::Ed25519(Ed25519::from((hi_1, lo_1)));
+
+ assert(!signature_1.is_secp256r1());
+ assert(signature_2.is_secp256r1());
+ assert(!signature_3.is_secp256r1());
+}
+
+#[test]
+fn signature_is_ed25519() {
+ let hi_1 = 0xbd0c9b8792876713afa8bff383eebf31c43437823ed761cc3600d0016de5110c;
+ let lo_1 = 0x44ac566bd156b4fc71a4a4cb2655d3dd360c695edb17dc3b64d611e122fea23d;
+ let signature_1 = Signature::Secp256k1(Secp256k1::from((hi_1, lo_1)));
+ let signature_2 = Signature::Secp256r1(Secp256r1::from((hi_1, lo_1)));
+ let signature_3 = Signature::Ed25519(Ed25519::from((hi_1, lo_1)));
+
+ assert(!signature_1.is_ed25519());
+ assert(!signature_2.is_ed25519());
+ assert(signature_3.is_ed25519());
+}
+
+#[test]
+fn signature_bits() {
+ let new_secp256r1 = Secp256r1::new();
+ let new_secp256k1 = Secp256r1::new();
+ let new_ed25519 = Ed25519::new();
+
+ let secp256r1_bits = new_secp256r1.bits();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(secp256r1_bits[iter] == 0u8);
+ iter += 1;
+ }
+
+ let secp256k1_bits = new_secp256k1.bits();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(secp256k1_bits[iter] == 0u8);
+ iter += 1;
+ }
+
+ let ed25519_bits = new_ed25519.bits();
+ let mut iter = 0;
+ while iter < 64 {
+ assert(ed25519_bits[iter] == 0u8);
+ iter += 1;
+ }
+}