diff --git a/onchain/src/bip340.cairo b/onchain/src/bip340.cairo index 49b7f6d7..fde59260 100644 --- a/onchain/src/bip340.cairo +++ b/onchain/src/bip340.cairo @@ -10,8 +10,7 @@ use core::to_byte_array::{AppendFormattedToByteArray, FormatAsByteArray}; use core::traits::Into; use starknet::{secp256k1::{Secp256k1Point}, secp256_trait::{Secp256Trait, Secp256PointTrait}}; -use alexandria_math::sha256::sha256; -use joyboy::utils::{shl, shr}; +use joyboy::utils::{shl, shr, compute_sha256_byte_array}; const TWO_POW_32: u128 = 0x100000000; const TWO_POW_64: u128 = 0x10000000000000000; @@ -19,57 +18,6 @@ const TWO_POW_96: u128 = 0x1000000000000000000000000; const p: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F; -fn compute_sha256_byte_array(m: @ByteArray) -> [u32; 8] { - let mut ba = ArrayTrait::new(); - let len = m.len(); - let mut i = 0; - loop { - if i == len { - break (); - } - ba.append(m.at(i).unwrap()); - i += 1; - }; - - let sha = sha256(ba); - - let r = [ - shl((*sha.at(0)).into(), 24_u32) - + shl((*sha.at(1)).into(), 16_u32) - + shl((*sha.at(2)).into(), 8_u32) - + (*sha.at(3)).into(), - shl((*sha.at(4)).into(), 24_u32) - + shl((*sha.at(5)).into(), 16_u32) - + shl((*sha.at(6)).into(), 8_u32) - + (*sha.at(7)).into(), - shl((*sha.at(8)).into(), 24_u32) - + shl((*sha.at(9)).into(), 16_u32) - + shl((*sha.at(10)).into(), 8_u32) - + (*sha.at(11)).into(), - shl((*sha.at(12)).into(), 24_u32) - + shl((*sha.at(13)).into(), 16_u32) - + shl((*sha.at(14)).into(), 8_u32) - + (*sha.at(15)).into(), - shl((*sha.at(16)).into(), 24_u32) - + shl((*sha.at(17)).into(), 16_u32) - + shl((*sha.at(18)).into(), 8_u32) - + (*sha.at(19)).into(), - shl((*sha.at(20)).into(), 24_u32) - + shl((*sha.at(21)).into(), 16_u32) - + shl((*sha.at(22)).into(), 8_u32) - + (*sha.at(23)).into(), - shl((*sha.at(24)).into(), 24_u32) - + shl((*sha.at(25)).into(), 16_u32) - + shl((*sha.at(26)).into(), 8_u32) - + (*sha.at(27)).into(), - shl((*sha.at(28)).into(), 24_u32) - + shl((*sha.at(29)).into(), 16_u32) - + shl((*sha.at(30)).into(), 8_u32) - + (*sha.at(31)).into(), - ]; - - r -} /// Computes BIP0340/challenge tagged hash. /// @@ -146,7 +94,7 @@ fn hash_challenge(rx: u256, px: u256, m: ByteArray) -> u256 { /// # Returns /// Returns `true` if the signature is valid for the given message and public key; otherwise, /// returns `false`. -fn verify(px: u256, rx: u256, s: u256, m: ByteArray) -> bool { +pub fn verify(px: u256, rx: u256, s: u256, m: ByteArray) -> bool { let n = Secp256Trait::::get_curve_size(); if px >= p || rx >= p || s >= n { diff --git a/onchain/src/social/request.cairo b/onchain/src/social/request.cairo index 4c34fd75..26846cc7 100644 --- a/onchain/src/social/request.cairo +++ b/onchain/src/social/request.cairo @@ -1,4 +1,12 @@ +use core::to_byte_array::FormatAsByteArray; use core::fmt::Display; +use core::traits::Into; +use joyboy::utils::{compute_sha256_byte_array}; +use joyboy::bip340; + +const TWO_POW_32: u128 = 0x100000000; +const TWO_POW_64: u128 = 0x10000000000000000; +const TWO_POW_96: u128 = 0x1000000000000000000000000; #[derive(Copy, Drop, Debug)] pub struct Signature { @@ -17,11 +25,28 @@ pub struct SocialRequest> { } pub fn verify>(request: @SocialRequest) -> bool { - // TODO: implement verification - // println!("{}", request.pubkey); - // println!("{}", request.content); - // println!("{:?}", request.sig); - false + let id = @format!( + "[0,\"{}\",{},{},{},\"{}\"]", + request.pubkey.format_as_byte_array(16), + request.created_at, + request.kind, + request.tags, + request.content + ); + + let [x0, x1, x2, x3, x4, x5, x6, x7] = compute_sha256_byte_array(id); + + let mut ba = Default::default(); + ba.append_word(x0.into(), 4); + ba.append_word(x1.into(), 4); + ba.append_word(x2.into(), 4); + ba.append_word(x3.into(), 4); + ba.append_word(x4.into(), 4); + ba.append_word(x5.into(), 4); + ba.append_word(x6.into(), 4); + ba.append_word(x7.into(), 4); + + bip340::verify(*request.pubkey, *request.sig.r, *request.sig.s, ba) } #[cfg(test)] @@ -29,16 +54,165 @@ mod tests { use super::{Signature, SocialRequest, verify}; #[test] - fn test_wip() { - // TODO: complete the test + fn verify_valid_signature() { let r: SocialRequest = SocialRequest { - pubkey: 123_u256, - created_at: 1_u64, - kind: 0_u16, - tags: "", + pubkey: 0xa2611fdbcbcc1e43ef809341ddef4a98c15ff6e6410ff7ed0c2b1c4f2a2cc2f5_u256, + created_at: 1716380267_u64, + kind: 1_u16, + tags: "[]", content: "abc", - sig: Signature { r: 1_u256, s: 2_u256 } + sig: Signature { + r: 0xd6891392ca5384da7b3e471380c9927a66a71c3cf9f3e6cd4d69813fd5258274_u256, + s: 0x39cd462e61f6e4a7a677989da9fe6625c45979f6e23513bd8eaa81aa5c38c693_u256 + } + }; + + assert!(verify(@r)); + } + + #[test] + fn verify_signature_long_content() { + let r: SocialRequest = SocialRequest { + pubkey: 0xa2611fdbcbcc1e43ef809341ddef4a98c15ff6e6410ff7ed0c2b1c4f2a2cc2f5_u256, + created_at: 1716403778_u64, + kind: 1_u16, + tags: "[]", + content: "nprofile1qys8wumn8ghj7un9d3shjtn2daukymme9e3k7mtdw4hxjare9e3k7mgqyzzxqw6wxqyyqqmv4rxgz2l0ej8zgrqfkuupycuatnwcannad6ayqx7zdcy send 1 USDC to nprofile1qqs2sa3zk4a49umxg4lgvlsaenrqaf33ejkffd78f2cgy4xy38h393s2w22mm", + sig: Signature { + r: 0x4fda18c929f820f7f93f310f4fa9a8f2efcdd544539f4ce24fe2daf4f68d0b2d_u256, + s: 0x279537893013f5849a716ac48e89ab4f8ce94871986326494c7311fc956639c3_u256 + } + }; + + assert!(verify(@r)); + } + + #[test] + fn verify_valid_signature_tags() { + let r: SocialRequest = SocialRequest { + pubkey: 0xcbddbb8b79e395d6458b49aa315b74fcc26d4d8d722e0a6421b4e04a612fc51c_u256, + created_at: 1716285235_u64, + kind: 1_u16, + tags: "[[\"e\",\"5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36\"]]", + content: "joyboy", + sig: Signature { + r: 0x206e086fe298bf0733b0b22316721636ae7d8ce025c76baf83b8a31efaec8821_u256, + s: 0x494452ba56fd465a0d69baa1ff4af9efcb1d0af8f107473ce33877d7a1034a8e_u256 + } + }; + + assert!(verify(@r)); + } + + #[test] + fn verify_invalid_tags() { + // valid tags = + // "[[\"e\",\"5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36\"]]" + let r: SocialRequest = SocialRequest { + pubkey: 0xcbddbb8b79e395d6458b49aa315b74fcc26d4d8d722e0a6421b4e04a612fc51c_u256, + created_at: 1716285235_u64, + kind: 1_u16, + tags: "[]", + content: "joyboy", + sig: Signature { + r: 0x206e086fe298bf0733b0b22316721636ae7d8ce025c76baf83b8a31efaec8821_u256, + s: 0x494452ba56fd465a0d69baa1ff4af9efcb1d0af8f107473ce33877d7a1034a8e_u256 + } }; - verify(@r); + + assert!(!verify(@r)); + } + + #[test] + fn verify_invalid_content() { + // valid content = + // "nprofile1qys8wumn8ghj7un9d3shjtn2daukymme9e3k7mtdw4hxjare9e3k7mgqyzzxqw6wxqyyqqmv4rxgz2l0ej8zgrqfkuupycuatnwcannad6ayqx7zdcy + // send 1 USDC to nprofile1qqs2sa3zk4a49umxg4lgvlsaenrqaf33ejkffd78f2cgy4xy38h393s2w22mm" + let r: SocialRequest = SocialRequest { + pubkey: 0xa2611fdbcbcc1e43ef809341ddef4a98c15ff6e6410ff7ed0c2b1c4f2a2cc2f5_u256, + created_at: 1716403778_u64, + kind: 1_u16, + tags: "[]", + content: "", + sig: Signature { + r: 0x4fda18c929f820f7f93f310f4fa9a8f2efcdd544539f4ce24fe2daf4f68d0b2d_u256, + s: 0x279537893013f5849a716ac48e89ab4f8ce94871986326494c7311fc956639c3_u256 + } + }; + + assert!(!verify(@r)); + } + + #[test] + fn verify_invalid_pubkey() { + // valid pubkey = 0xa2611fdbcbcc1e43ef809341ddef4a98c15ff6e6410ff7ed0c2b1c4f2a2cc2f5_u256 + let r: SocialRequest = SocialRequest { + pubkey: 0xa2611fdbcbcc1e43ef809341ddef4a98c15ff6e6410ff7ed0c2b1c4f2a2cc2f4_u256, + created_at: 1716380267_u64, + kind: 1_u16, + tags: "[]", + content: "abc", + sig: Signature { + r: 0xd6891392ca5384da7b3e471380c9927a66a71c3cf9f3e6cd4d69813fd5258274_u256, + s: 0x39cd462e61f6e4a7a677989da9fe6625c45979f6e23513bd8eaa81aa5c38c693_u256 + } + }; + + assert!(!verify(@r)); + } + + #[test] + fn verify_invalid_timestamp() { + // valid timestamp = 1716285235 + let r: SocialRequest = SocialRequest { + pubkey: 0xcbddbb8b79e395d6458b49aa315b74fcc26d4d8d722e0a6421b4e04a612fc51c_u256, + created_at: 1716285236_u64, + kind: 1_u16, + tags: "[[\"e\",\"5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36\"]]", + content: "joyboy", + sig: Signature { + r: 0x206e086fe298bf0733b0b22316721636ae7d8ce025c76baf83b8a31efaec8821_u256, + s: 0x494452ba56fd465a0d69baa1ff4af9efcb1d0af8f107473ce33877d7a1034a8e_u256 + } + }; + + assert!(!verify(@r)); + } + + #[test] + fn verify_invalid_signature_r() { + // valid sig[0:32] = 0x206e086fe298bf0733b0b22316721636ae7d8ce025c76baf83b8a31efaec8821 + let r: SocialRequest = SocialRequest { + pubkey: 0xcbddbb8b79e395d6458b49aa315b74fcc26d4d8d722e0a6421b4e04a612fc51c_u256, + created_at: 1716285235_u64, + kind: 1_u16, + tags: "[[\"e\",\"5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36\"]]", + content: "joyboy", + sig: Signature { + r: 0x206e086fe298bf0733b0b22316721636ae7d8ce025c76baf83b8a31efaec8822_u256, + s: 0x494452ba56fd465a0d69baa1ff4af9efcb1d0af8f107473ce33877d7a1034a8e_u256 + } + }; + + assert!(!verify(@r)); + } + + #[test] + fn verify_invalid_signature_s() { + // valid sig[32:64] = 0x494452ba56fd465a0d69baa1ff4af9efcb1d0af8f107473ce33877d7a1034a8e + let r: SocialRequest = SocialRequest { + pubkey: 0xcbddbb8b79e395d6458b49aa315b74fcc26d4d8d722e0a6421b4e04a612fc51c_u256, + created_at: 1716285235_u64, + kind: 1_u16, + tags: "[[\"e\",\"5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36\"]]", + content: "joyboy", + sig: Signature { + r: 0x206e086fe298bf0733b0b22316721636ae7d8ce025c76baf83b8a31efaec8821_u256, + s: 0x494452ba56fd465a0d69baa1ff4af9efcb1d0af8f107473ce33877d7a1034a8a_u256 + } + }; + + assert!(!verify(@r)); } } + diff --git a/onchain/src/utils.cairo b/onchain/src/utils.cairo index 5598afde..1b2def47 100644 --- a/onchain/src/utils.cairo +++ b/onchain/src/utils.cairo @@ -1,4 +1,5 @@ use core::integer::{u32_wide_mul, u8_wide_mul, BoundedInt}; +use alexandria_math::sha256::sha256; trait Pow2 { #[inline] @@ -101,3 +102,55 @@ pub fn shl< ) -> V { (WideMul::wide_mul(x, Pow2::pow2(n)) & BoundedInt::::max().into()).try_into().unwrap() } + +pub fn compute_sha256_byte_array(m: @ByteArray) -> [u32; 8] { + let mut ba = ArrayTrait::new(); + let len = m.len(); + let mut i = 0; + loop { + if i == len { + break (); + } + ba.append(m.at(i).unwrap()); + i += 1; + }; + + let sha = sha256(ba); + + let r = [ + shl((*sha.at(0)).into(), 24_u32) + + shl((*sha.at(1)).into(), 16_u32) + + shl((*sha.at(2)).into(), 8_u32) + + (*sha.at(3)).into(), + shl((*sha.at(4)).into(), 24_u32) + + shl((*sha.at(5)).into(), 16_u32) + + shl((*sha.at(6)).into(), 8_u32) + + (*sha.at(7)).into(), + shl((*sha.at(8)).into(), 24_u32) + + shl((*sha.at(9)).into(), 16_u32) + + shl((*sha.at(10)).into(), 8_u32) + + (*sha.at(11)).into(), + shl((*sha.at(12)).into(), 24_u32) + + shl((*sha.at(13)).into(), 16_u32) + + shl((*sha.at(14)).into(), 8_u32) + + (*sha.at(15)).into(), + shl((*sha.at(16)).into(), 24_u32) + + shl((*sha.at(17)).into(), 16_u32) + + shl((*sha.at(18)).into(), 8_u32) + + (*sha.at(19)).into(), + shl((*sha.at(20)).into(), 24_u32) + + shl((*sha.at(21)).into(), 16_u32) + + shl((*sha.at(22)).into(), 8_u32) + + (*sha.at(23)).into(), + shl((*sha.at(24)).into(), 24_u32) + + shl((*sha.at(25)).into(), 16_u32) + + shl((*sha.at(26)).into(), 8_u32) + + (*sha.at(27)).into(), + shl((*sha.at(28)).into(), 24_u32) + + shl((*sha.at(29)).into(), 16_u32) + + shl((*sha.at(30)).into(), 8_u32) + + (*sha.at(31)).into(), + ]; + + r +}