signature_verify.rs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // SPDX-License-Identifier: Apache-2.0
  2. use crate::{build_solidity, Account, AccountState, BorshToken};
  3. use base58::FromBase58;
  4. use ed25519_dalek::{Signature, Signer, SigningKey};
  5. use rand::rngs::OsRng;
  6. use serde_derive::Serialize;
  7. use std::convert::TryInto;
  8. use std::mem::size_of;
  9. #[derive(Serialize)]
  10. #[repr(C)]
  11. struct Instructions {
  12. num_instructions: u16,
  13. instruction_offset: u16,
  14. num_accounts: u16,
  15. /* assume no accounts */
  16. program_id: [u8; 32],
  17. instruction_len: u16,
  18. }
  19. #[derive(Serialize)]
  20. #[repr(C)]
  21. pub struct Ed25519SignatureOffsets {
  22. num_signatures: u8,
  23. padding: u8,
  24. signature_offset: u16, // offset to ed25519 signature of 64 bytes
  25. signature_instruction_index: u16, // instruction index to find signature
  26. public_key_offset: u16, // offset to public key of 32 bytes
  27. public_key_instruction_index: u16, // instruction index to find public key
  28. message_data_offset: u16, // offset to start of message data
  29. message_data_size: u16, // size of message data
  30. message_instruction_index: u16, // index of instruction data to get message data
  31. }
  32. #[test]
  33. fn verify() {
  34. let mut vm = build_solidity(
  35. r#"
  36. contract foo {
  37. function verify(address addr, bytes message, bytes signature) public returns (bool) {
  38. return signatureVerify(addr, message, signature);
  39. }
  40. }"#,
  41. );
  42. let data_account = vm.initialize_data_account();
  43. vm.function("new")
  44. .accounts(vec![("dataAccount", data_account)])
  45. .call();
  46. let instructions_account: Account = "Sysvar1nstructions1111111111111111111111111"
  47. .from_base58()
  48. .unwrap()
  49. .try_into()
  50. .unwrap();
  51. vm.account_data
  52. .insert(instructions_account, AccountState::default());
  53. let mut csprng = OsRng;
  54. let keypair: SigningKey = SigningKey::generate(&mut csprng);
  55. let message: &[u8] =
  56. b"This is a test of the ed25519 sig check for the ed25519 signature check program";
  57. let signature: Signature = keypair.sign(message);
  58. let signature_bs = signature.to_bytes().to_vec();
  59. println!(
  60. "T: PUB: {}",
  61. hex::encode(keypair.verifying_key().to_bytes())
  62. );
  63. println!("T: SIG: {}", hex::encode(&signature_bs));
  64. println!("T: MES: {}", hex::encode(message));
  65. let returns = vm
  66. .function("verify")
  67. .arguments(&[
  68. BorshToken::Address(keypair.verifying_key().to_bytes()),
  69. BorshToken::Bytes(message.to_vec()),
  70. BorshToken::Bytes(signature_bs.clone()),
  71. ])
  72. .accounts(vec![("SysvarInstruction", instructions_account)])
  73. .call()
  74. .unwrap();
  75. assert_eq!(returns, BorshToken::Bool(false));
  76. let instructions_account: Account = "Sysvar1nstructions1111111111111111111111111"
  77. .from_base58()
  78. .unwrap()
  79. .try_into()
  80. .unwrap();
  81. let instructions =
  82. encode_instructions(&keypair.verifying_key().to_bytes(), &signature_bs, message);
  83. vm.account_data.insert(
  84. instructions_account,
  85. AccountState {
  86. data: instructions,
  87. owner: None,
  88. lamports: 0,
  89. },
  90. );
  91. println!("Now try for real");
  92. let returns = vm
  93. .function("verify")
  94. .arguments(&[
  95. BorshToken::Address(keypair.verifying_key().to_bytes()),
  96. BorshToken::Bytes(message.to_vec()),
  97. BorshToken::Bytes(signature_bs.clone()),
  98. ])
  99. .accounts(vec![("SysvarInstruction", instructions_account)])
  100. .call()
  101. .unwrap();
  102. assert_eq!(returns, BorshToken::Bool(true));
  103. println!("now try with bad signature");
  104. // flip a bit and make sure it no longer verifies
  105. let mut signature_copy = signature_bs.clone();
  106. signature_copy[2] ^= 0x80;
  107. let instructions = encode_instructions(
  108. &keypair.verifying_key().to_bytes(),
  109. &signature_copy,
  110. message,
  111. );
  112. vm.account_data.insert(
  113. instructions_account,
  114. AccountState {
  115. data: instructions,
  116. owner: None,
  117. lamports: 0,
  118. },
  119. );
  120. let returns = vm
  121. .function("verify")
  122. .arguments(&[
  123. BorshToken::Address(keypair.verifying_key().to_bytes()),
  124. BorshToken::Bytes(message.to_vec()),
  125. BorshToken::Bytes(signature_bs),
  126. ])
  127. .accounts(vec![("SysvarInstruction", instructions_account)])
  128. .call()
  129. .unwrap();
  130. assert_eq!(returns, BorshToken::Bool(false));
  131. }
  132. fn encode_instructions(public_key: &[u8], signature: &[u8], message: &[u8]) -> Vec<u8> {
  133. let offsets = Ed25519SignatureOffsets {
  134. num_signatures: 1,
  135. padding: 0,
  136. signature_offset: size_of::<Ed25519SignatureOffsets>() as u16,
  137. signature_instruction_index: 0,
  138. public_key_offset: (size_of::<Ed25519SignatureOffsets>() + signature.len()) as u16,
  139. public_key_instruction_index: 0,
  140. message_data_offset: (size_of::<Ed25519SignatureOffsets>()
  141. + signature.len()
  142. + public_key.len()) as u16,
  143. message_instruction_index: 0,
  144. message_data_size: message.len() as u16,
  145. };
  146. let mut ed25519_instruction = bincode::serialize(&offsets).unwrap();
  147. ed25519_instruction.extend_from_slice(signature);
  148. ed25519_instruction.extend_from_slice(public_key);
  149. ed25519_instruction.extend_from_slice(message);
  150. let instr = Instructions {
  151. num_instructions: 1,
  152. instruction_offset: 4,
  153. num_accounts: 0,
  154. program_id: "Ed25519SigVerify111111111111111111111111111"
  155. .from_base58()
  156. .unwrap()
  157. .try_into()
  158. .unwrap(),
  159. instruction_len: ed25519_instruction.len() as u16,
  160. };
  161. let mut instructions = bincode::serialize(&instr).unwrap();
  162. instructions.extend_from_slice(&ed25519_instruction);
  163. instructions
  164. }