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; + } +}