Skip to content

Commit

Permalink
Verify SocialPay request (keep-starknet-strange#91)
Browse files Browse the repository at this point in the history
* wip

* refac: implement a function to verify NIP01Event signature using bip340 (keep-starknet-strange#71)

* refac: make it work on CI

* refac: convert sha256 directly into ByteArray

* test: add more test coverage

* refac: implicitly return verify
test: add test for invalid cases

* test: refactor fn names and assert statements

* remove debug messages

---------

Co-authored-by: Emmaunuel Ejembi <[email protected]>
  • Loading branch information
maciejka and EjembiEmmanuel authored May 23, 2024
1 parent 8713a12 commit 67fc99f
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 67 deletions.
56 changes: 2 additions & 54 deletions onchain/src/bip340.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,66 +10,14 @@ 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;
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.
///
Expand Down Expand Up @@ -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::<Secp256k1Point>::get_curve_size();

if px >= p || rx >= p || s >= n {
Expand Down
200 changes: 187 additions & 13 deletions onchain/src/social/request.cairo
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -17,28 +25,194 @@ pub struct SocialRequest<C, +Display<C>> {
}

pub fn verify<C, +Display<C>>(request: @SocialRequest<C>) -> 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)]
mod tests {
use super::{Signature, SocialRequest, verify};

#[test]
fn test_wip() {
// TODO: complete the test
fn verify_valid_signature() {
let r: SocialRequest<ByteArray> = 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<ByteArray> = 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<ByteArray> = 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<ByteArray> = 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<ByteArray> = 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<ByteArray> = 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<ByteArray> = 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<ByteArray> = 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<ByteArray> = 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));
}
}

53 changes: 53 additions & 0 deletions onchain/src/utils.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use core::integer::{u32_wide_mul, u8_wide_mul, BoundedInt};
use alexandria_math::sha256::sha256;

trait Pow2<V, N> {
#[inline]
Expand Down Expand Up @@ -101,3 +102,55 @@ pub fn shl<
) -> V {
(WideMul::wide_mul(x, Pow2::pow2(n)) & BoundedInt::<V>::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
}

0 comments on commit 67fc99f

Please sign in to comment.