Skip to content

Commit

Permalink
update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
robert-zaremba committed Aug 10, 2023
1 parent fe92afe commit f19af48
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 122 deletions.
1 change: 0 additions & 1 deletion contracts/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion contracts/oracle/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ sbt = { path = "../sbt" }
[dev-dependencies]
rand = "^0.7"
near-primitives.workspace = true
near-crypto.workspace = true
ed25519-dalek.workspace = true

# integration tests
Expand Down
2 changes: 1 addition & 1 deletion contracts/oracle/src/checks.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(all(test, not(target_arch = "wasm32")))]
pub mod tests {

use crate::*;

pub fn deserialize_claim(claim_b64: &str) -> Claim {
let c_bz = crate::b64_decode("claim", claim_b64.to_string()).unwrap();
let c = Claim::try_from_slice(&c_bz).unwrap();
Expand Down
88 changes: 10 additions & 78 deletions contracts/oracle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub struct Contract {
/// SBT ttl until expire in miliseconds (expire=issue_time+sbt_ttl)
pub sbt_ttl_ms: u64,
/// ed25519 pub key (could be same as a NEAR pub key)
pub authority_pubkey: [u8; PUBLIC_KEY_LENGTH], // Vec<u8>,
pub authority_pubkey: [u8; PUBLIC_KEY_LEN], // Vec<u8>,
pub used_identities: UnorderedSet<Vec<u8>>,

/// used for backend key rotation
Expand Down Expand Up @@ -110,7 +110,8 @@ impl Contract {
**********/

/// Mints a new SBT for the transaction signer.
/// @claim_b64: standard base64 borsh serialized Claim (same bytes as used for the claim signature)
/// @claim_b64: standard base64 borsh serialized Claim (same bytes as used for the claim signature).
/// @claim_sig: standard base64 serialized ed25519 signature.
/// If `metadata.expires_at` is None then we set it to ` now+self.ttl`.
/// Panics if `metadata.expires_at > now+self.ttl`.
// TODO: update result to return TokenId
Expand All @@ -132,9 +133,8 @@ impl Contract {
let claim_bytes = b64_decode("claim_b64", claim_b64)?;
let claim = Claim::try_from_slice(&claim_bytes)
.map_err(|_| CtrError::Borsh("claim".to_string()))?;
let signature = b64_decode("sign_b64", claim_sig)?;
let signature: [u8; 64] = signature.try_into().expect("signature must be 64 bytes");
verify_claim(&self.authority_pubkey, claim_bytes, &signature)?;
let signature = b64_decode("claim_sig", claim_sig)?;
verify_claim(&signature, &claim_bytes, &self.authority_pubkey)?;

if claim.verified_kyc {
require!(
Expand Down Expand Up @@ -320,23 +320,12 @@ mod checks;

#[cfg(all(test, not(target_arch = "wasm32")))]
pub mod tests {
extern crate ed25519_dalek;
extern crate rand;

use crate::*;
use ed25519_dalek::Keypair;
use near_sdk::test_utils::VMContextBuilder;
use near_sdk::{testing_env, VMContext};

use ed25519_dalek::{Keypair, Signer};
use rand::rngs::OsRng;

pub fn b64_encode(data: Vec<u8>) -> String {
near_sdk::base64::encode(data)
}

fn acc_claimer() -> AccountId {
"user1.near".parse().unwrap()
}
use crate::util::tests::{acc_claimer, b64_encode, gen_key, mk_claim_sign};

fn acc_u1() -> AccountId {
"user2.near".parse().unwrap()
Expand Down Expand Up @@ -380,9 +369,7 @@ pub mod tests {
.is_view(false)
.build();

let mut csprng = OsRng {};
let keypair: Keypair = Keypair::generate(&mut csprng);

let keypair = gen_key();
let ctr = Contract::new(
b64_encode(keypair.public.to_bytes().to_vec()),
ContractMetadata {
Expand All @@ -403,35 +390,6 @@ pub mod tests {
return (ctx, ctr, keypair);
}

/// @timestamp: in seconds
pub fn mk_claim(timestamp: u64, external_id: &str, is_verified_kyc: bool) -> Claim {
Claim {
claimer: acc_claimer(),
external_id: external_id.to_string(),
timestamp,
verified_kyc: is_verified_kyc,
}
}

// returns b64 serialized claim and signature
fn sign_claim(c: &Claim, k: &Keypair) -> (String, String) {
let c_bz = c.try_to_vec().unwrap();
let sig = k.sign(&c_bz);
let sig_bz = sig.to_bytes();
(b64_encode(c_bz), b64_encode(sig_bz.to_vec()))
}

fn mk_claim_sign(
timestamp: u64,
external_id: &str,
k: &Keypair,
is_verified_kyc: bool,
) -> (Claim, String, String) {
let c = mk_claim(timestamp, external_id, is_verified_kyc);
let (c_str, sig) = sign_claim(&c, &k);
return (c, c_str, sig);
}

fn assert_bad_request(resp: Result<Promise, CtrError>, expected_msg: &str) {
match resp {
Err(CtrError::BadRequest(s)) => {
Expand Down Expand Up @@ -546,9 +504,8 @@ pub mod tests {
let claim_sig_b64 = "38X2TnWgc6moc4zReAJFQ7BjtOUlWZ+i3YQl9gSMOXwnm5gupfHV/YGmGPOek6SSkotT586d4zTTT2U8Qh3GBw==".to_owned();

let claim_bytes = b64_decode("claim_b64", claim_b64.clone()).unwrap();
let signature = b64_decode("sign_b64", claim_sig_b64.clone()).unwrap();
let signature: [u8; 64] = signature.try_into().expect("signature must be 64 bytes");
verify_claim(&ctr.authority_pubkey, claim_bytes, &signature).unwrap();
let signature = b64_decode("sig_b64", claim_sig_b64.clone()).unwrap();
verify_claim(&signature, &claim_bytes, &ctr.authority_pubkey).unwrap();

let r = ctr.sbt_mint(claim_b64, claim_sig_b64, None);
match r {
Expand Down Expand Up @@ -619,29 +576,4 @@ pub mod tests {
Ok(_) => panic!("expected DuplicatedID, got: Ok"),
}
}

#[test]
fn pubkey() {
let pk_bytes = pubkey_from_b64("kSj7W/TdN9RGLgdJA8ac7i/WdQdm2lwQ1IPGlO1L3xc=".to_string());
assert_ne!(pk_bytes[0], 0);

let mut csprng = OsRng {};
let k = Keypair::generate(&mut csprng);

let (_, c_str, sig) = mk_claim_sign(start() / SECOND, "0x12", &k, false);
let claim_bytes = b64_decode("claim_b64", c_str).unwrap();
let signature = b64_decode("sign_b64", sig).unwrap();
let signature: [u8; 64] = signature.try_into().expect("signature must be 64 bytes");
let res = verify_claim(&k.public.to_bytes(), claim_bytes, &signature);
assert!(res.is_ok(), "verification result: {:?}", res);
}

#[test]
fn claim_serialization() {
let c = mk_claim(1677621259142, "some_111#$!", false);
let claim_bz = c.try_to_vec().unwrap();
let claim_str = b64_encode(claim_bz);
let claim2 = checks::tests::deserialize_claim(&claim_str);
assert_eq!(c, claim2, "serialization should work");
}
}
144 changes: 103 additions & 41 deletions contracts/oracle/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use uint::hex;

pub use crate::errors::*;

pub const PUBLIC_KEY_LENGTH: usize = 32;
pub const PUBLIC_KEY_LEN: usize = 32;
pub const SIGNATURE_LEN: usize = 64;

type CtrResult<T> = Result<T, CtrError>;

Expand Down Expand Up @@ -34,7 +35,7 @@ pub fn b64_decode(arg: &str, data: String) -> CtrResult<Vec<u8>> {
})
}

pub fn pubkey_from_b64(pubkey: String) -> [u8; PUBLIC_KEY_LENGTH] {
pub fn pubkey_from_b64(pubkey: String) -> [u8; PUBLIC_KEY_LEN] {
let pk_bz = base64::decode(pubkey).expect("authority_pubkey is not a valid standard base64");
pk_bz.try_into().expect("authority pubkey must be 32 bytes")
}
Expand All @@ -54,34 +55,43 @@ mod sys {
}

#[cfg(not(all(test, not(target_arch = "wasm32"))))]
pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], public_key: &[u8; 32]) -> bool {
pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], pubkey: &[u8; 32]) -> bool {
unsafe {
sys::ed25519_verify(
signature.len() as _,
signature.as_ptr() as _,
message.len() as _,
message.as_ptr() as _,
public_key.len() as _,
public_key.as_ptr() as _,
pubkey.len() as _,
pubkey.as_ptr() as _,
) == 1
}
}

#[cfg(test)]
use ed25519_dalek::{PublicKey, Signature, Verifier};

#[cfg(all(test, not(target_arch = "wasm32")))]
pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], public_key: &[u8; 32]) -> bool {
return true;
pub fn ed25519_verify(signature: &[u8; 64], message: &[u8], pubkey: &[u8; 32]) -> bool {
let pk = PublicKey::from_bytes(pubkey).unwrap();
match Signature::from_bytes(signature) {
Ok(sig) => pk.verify(message, &sig).is_ok(),
Err(_) => false,
}
}

pub fn verify_claim(
pubkey: &[u8; PUBLIC_KEY_LENGTH],
claim: Vec<u8>,
claim_sig: &[u8; 64],
claim_sig: &Vec<u8>,
claim: &Vec<u8>,
pubkey: &[u8; PUBLIC_KEY_LEN],
) -> Result<(), CtrError> {
let valid = ed25519_verify(claim_sig, &claim, pubkey);
if !valid {
return Err(CtrError::Signature("invalid signature".to_string()));
} else {
Ok(())
let claim_sig: &[u8; SIGNATURE_LEN] = claim_sig
.as_slice()
.try_into()
.expect("signature must be 64 bytes");
match ed25519_verify(claim_sig, claim, pubkey) {
true => Ok(()),
false => Err(CtrError::Signature("invalid signature".to_string())),
}
}

Expand Down Expand Up @@ -113,10 +123,58 @@ pub(crate) fn is_supported_account(account: Chars) -> bool {
}

#[cfg(all(test, not(target_arch = "wasm32")))]
mod tests {
pub mod tests {
extern crate ed25519_dalek;
extern crate rand;
use ed25519_dalek::{Keypair, Signer};
use rand::rngs::OsRng;

use uint::hex::FromHexError;

use super::*;
use crate::checks::tests::deserialize_claim;

pub fn gen_key() -> Keypair {
let mut csprng = OsRng {};
Keypair::generate(&mut csprng)
}

pub fn acc_claimer() -> AccountId {
"user1.near".parse().unwrap()
}

pub fn b64_encode(data: Vec<u8>) -> String {
near_sdk::base64::encode(data)
}

/// @timestamp: in seconds
pub fn mk_claim(timestamp: u64, external_id: &str, is_verified_kyc: bool) -> Claim {
Claim {
claimer: acc_claimer(),
external_id: external_id.to_string(),
timestamp,
verified_kyc: is_verified_kyc,
}
}

// returns b64 serialized claim and signature
pub fn sign_claim(c: &Claim, k: &Keypair) -> (String, String) {
let c_bz = c.try_to_vec().unwrap();
let sig = k.sign(&c_bz);
let sig_bz = sig.to_bytes();
(b64_encode(c_bz), b64_encode(sig_bz.to_vec()))
}

pub fn mk_claim_sign(
timestamp: u64,
external_id: &str,
k: &Keypair,
is_verified_kyc: bool,
) -> (Claim, String, String) {
let c = mk_claim(timestamp, external_id, is_verified_kyc);
let (c_str, sig) = sign_claim(&c, &k);
return (c, c_str, sig);
}

fn check_hex(s: &str, r: Vec<u8>) -> Result<(), FromHexError> {
let b = hex::decode(s)?;
Expand Down Expand Up @@ -155,34 +213,38 @@ mod tests {
}

#[test]
fn check_pub_key_len() {
assert_eq!(ed25519_dalek::PUBLIC_KEY_LENGTH, PUBLIC_KEY_LENGTH);
fn claim_serialization() {
let c = mk_claim(1677621259142, "some_111#$!", false);
let claim_bz = c.try_to_vec().unwrap();
let claim_str = b64_encode(claim_bz);
let claim2 = deserialize_claim(&claim_str);
assert_eq!(c, claim2, "serialization should work");
}

#[test]
fn pubkey_near_crypto() {
//let sk = near_crypto::SecretKey::from_str("ed25519:...").unwrap();
let sk = near_crypto::SecretKey::from_random(near_crypto::KeyType::ED25519);
let k = match sk.clone() {
near_crypto::SecretKey::ED25519(k) => ed25519_dalek::Keypair::from_bytes(&k.0).unwrap(),
_ => panic!("expecting ed25519 key"),
};

let pk_bs58 = near_sdk::bs58::encode(k.public).into_string();
let pk_b64 = near_sdk::base64::encode(k.public.as_bytes().to_vec());
let sk_str = near_sdk::bs58::encode(k.secret).into_string();
let sk_str2 = sk.to_string();
println!(
"pubkey_bs58={} pubkey_b64={}\nsecret={} {}",
pk_bs58, pk_b64, sk_str, sk_str2,
);

// let sk2 = near_crypto::SecretKey::from_str(
// "secp256k1:AxynSCWRr2RrBXbzcbykYTo5vPmCkMf35s1D1bXV8P51",
// )
// .unwrap();
// println!("\nsecp: {}, public: {}", sk2, sk2.public_key());
fn check_pub_key_len() {
assert_eq!(ed25519_dalek::PUBLIC_KEY_LENGTH, PUBLIC_KEY_LEN);
assert_eq!(ed25519_dalek::SIGNATURE_LENGTH, SIGNATURE_LEN);
}

// assert!(false);
#[test]
fn test_verify_claim() {
let k = gen_key();
let (_, c_str, sig) = mk_claim_sign(10000, "0x12", &k, false);
let claim_bytes = b64_decode("claim_b64", c_str).unwrap();
let signature = b64_decode("sign_b64", sig).unwrap();
let res = verify_claim(&signature, &claim_bytes, &k.public.to_bytes());
assert!(res.is_ok(), "verification result: {:?}", res);

let pk2 = gen_key().public;
// let pk_bs58 = near_sdk::bs58::encode(k.public).into_string();
// println!(">>> pub {:?}", b64_encode(pk2.as_bytes().to_vec()));
let res = verify_claim(&signature, &claim_bytes, pk2.as_bytes());
assert!(res.is_err(), "verification result: {:?}", res);

let pk3_bytes = pubkey_from_b64("FGoAI6DXghOSK2ZaKVT/5lSP4X4JkoQQphv1FD4YRto=".to_string());
assert_ne!(pk3_bytes[0], 0);
let res = verify_claim(&signature, &claim_bytes, &pk3_bytes);
assert!(res.is_err(), "verification result: {:?}", res);
}
}

0 comments on commit f19af48

Please sign in to comment.