neo3/neo_builder/transaction/
verification_script.rs

1use std::{
2	collections::HashMap,
3	fmt::{Debug, Formatter},
4	str::FromStr,
5};
6
7use getset::{Getters, Setters};
8use primitive_types::H160;
9use serde::{Deserialize, Serialize};
10
11use crate::{
12	crypto::Secp256r1PublicKey,
13	neo_crypto::utils::{FromHexString, ToHexString},
14	neo_types::{
15		script_hash::ScriptHashExtension, Address, OpCode, ScriptHash, StackItem, TypeError,
16	},
17	prelude::Bytes,
18};
19
20use crate::{
21	builder::{BuilderError, InteropService, ScriptBuilder},
22	codec::{Decoder, Encoder, NeoSerializable},
23	config::NeoConstants,
24	crypto::{HashableForVec, Secp256r1Signature},
25	var_size,
26};
27use hex;
28use num_bigint::BigInt;
29use num_traits::{ToPrimitive, Zero};
30use p256::pkcs8::der::Encode;
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash, Getters, Setters, Serialize, Deserialize)]
33pub struct VerificationScript {
34	#[getset(get = "pub", set = "pub")]
35	script: Bytes,
36}
37
38impl VerificationScript {
39	pub fn new() -> Self {
40		Self { script: Bytes::new() }
41	}
42
43	pub fn from(script: Bytes) -> Self {
44		Self { script: script.to_vec() }
45	}
46
47	pub fn from_public_key(public_key: &Secp256r1PublicKey) -> Self {
48		let mut builder = ScriptBuilder::new();
49		builder
50			.push_data(public_key.get_encoded(true))
51			.sys_call(InteropService::SystemCryptoCheckSig);
52		Self::from(builder.to_bytes())
53	}
54
55	pub fn from_multi_sig(public_keys: &mut [Secp256r1PublicKey], threshold: u8) -> Self {
56		// Build multi-sig script
57		let mut builder = ScriptBuilder::new();
58		builder.push_integer(BigInt::from(threshold));
59		public_keys.sort();
60		for key in public_keys.iter() {
61			builder.push_data(key.get_encoded(true));
62		}
63		builder
64			.push_integer(BigInt::from(public_keys.len()))
65			.sys_call(InteropService::SystemCryptoCheckMultiSig);
66		Self::from(builder.to_bytes())
67	}
68
69	/// Checks if this verification script is from a single signature account.
70	///
71	/// Returns `true` if this script is from a single signature account, otherwise `false`.
72	pub fn is_single_sig(&self) -> bool {
73		if self.script.len() != 40 {
74			return false;
75		}
76
77		let interop_service = &self.script[self.script.len() - 4..]; // Get the last 4 bytes
78		let interop_service_hex = interop_service.to_hex_string();
79
80		self.script[0] == OpCode::PushData1.opcode()
81			&& self.script[1] == 33
82			&& self.script[35] == OpCode::Syscall.opcode()
83			&& interop_service_hex == InteropService::SystemCryptoCheckSig.hash() // Assuming `hash` returns a hex string
84	}
85
86	/// Checks if this verification script is from a multi-signature account.
87	///
88	/// Returns `true` if this script is from a multi-signature account.
89	/// Otherwise returns `false`.
90	#[doc(hidden)]
91	pub fn is_multi_sig(&self) -> bool {
92		if self.script.len() < 42 {
93			return false;
94		}
95
96		let mut reader = Decoder::new(&self.script);
97
98		let threshold = match reader.by_ref().read_push_int() {
99			Ok(n) => n,
100			Err(_) => return false,
101		};
102		if !(1..=NeoConstants::MAX_PUBLIC_KEYS_PER_MULTI_SIG)
103			.contains(&(threshold.to_u32().unwrap()))
104		{
105			return false;
106		}
107
108		let mut m: BigInt = BigInt::zero();
109		while reader.by_ref().read_u8() == OpCode::PushData1.opcode() {
110			let len = reader.by_ref().read_u8();
111			if len != 33 {
112				return false;
113			}
114			reader.by_ref().read_encoded_ec_point();
115			m += 1;
116			reader.mark();
117		}
118
119		if !(m >= threshold && m <= BigInt::from(NeoConstants::MAX_PUBLIC_KEYS_PER_MULTI_SIG)) {
120			return false;
121		}
122
123		reader.reset();
124
125		if BigInt::from(reader.read_push_int().unwrap()) != m
126			|| reader.read_u8() != OpCode::Syscall.opcode()
127		{
128			return false;
129		}
130
131		let service_bytes = &reader.read_bytes(4).unwrap().to_hex_string();
132		let hash = &InteropService::SystemCryptoCheckMultiSig.hash(); //.from_hex().unwrap();
133																//assert_eq!(service_bytes, hash);
134		if service_bytes != hash {
135			return false;
136		}
137
138		// match reader.by_ref().read_var_int() {
139		// 	Ok(v) =>
140		// 		if BigInt::from(v) != m {
141		// 			return false
142		// 		},
143		// 	Err(_) => return false,
144		// }
145
146		// if reader.by_ref().read_u8() != OpCode::Syscall as u8 {
147		// 	return false
148		// }
149
150		true
151	}
152
153	// other methods
154	pub fn hash(&self) -> H160 {
155		let mut script_hash = self.script.sha256_ripemd160();
156		script_hash.reverse();
157		H160::from_slice(&script_hash)
158	}
159
160	pub fn get_signatures(&self) -> Vec<Secp256r1Signature> {
161		let mut reader = Decoder::new(&self.script);
162		let mut signatures = vec![];
163
164		while reader.by_ref().read_u8() == OpCode::PushData1 as u8 {
165			let len = reader.by_ref().read_u8();
166			let sig =
167				Secp256r1Signature::from_bytes(&reader.by_ref().read_bytes(len as usize).unwrap())
168					.unwrap();
169			signatures.push(sig);
170		}
171
172		signatures
173	}
174
175	pub fn get_public_keys(&self) -> Result<Vec<Secp256r1PublicKey>, BuilderError> {
176		if self.is_single_sig() {
177			let mut reader = Decoder::new(&self.script);
178			reader.by_ref().read_u8(); // skip pushdata1
179			reader.by_ref().read_u8(); // skip length
180
181			let mut point = [0; 33];
182			point.copy_from_slice(&reader.by_ref().read_bytes(33).unwrap());
183
184			let key = Secp256r1PublicKey::from_bytes(&point).unwrap();
185			return Ok(vec![key]);
186		}
187
188		if self.is_multi_sig() {
189			let mut reader = Decoder::new(&self.script);
190			reader.by_ref().read_var_int().unwrap(); // skip threshold
191
192			let mut keys = vec![];
193			while reader.by_ref().read_u8() == OpCode::PushData1 as u8 {
194				reader.by_ref().read_u8(); // skip length
195				let mut point = [0; 33];
196				point.copy_from_slice(&reader.by_ref().read_bytes(33).unwrap());
197				keys.push(Secp256r1PublicKey::from_bytes(&point).unwrap());
198			}
199
200			return Ok(keys);
201		}
202
203		Err(BuilderError::InvalidScript("Invalid verification script".to_string()))
204	}
205
206	pub fn get_signing_threshold(&self) -> Result<usize, BuilderError> {
207		if self.is_single_sig() {
208			Ok(1)
209		} else if self.is_multi_sig() {
210			let reader = &mut Decoder::new(&self.script);
211			Ok(reader.by_ref().read_push_int()?.to_usize().unwrap())
212		//Ok(reader.by_ref().read_bigint()?.to_usize().unwrap())
213		} else {
214			Err(BuilderError::InvalidScript("Invalid verification script".to_string()))
215		}
216	}
217
218	pub fn get_nr_of_accounts(&self) -> Result<usize, BuilderError> {
219		match self.get_public_keys() {
220			Ok(keys) => Ok(keys.len()),
221			Err(e) => Err(e),
222		}
223	}
224}
225
226impl NeoSerializable for VerificationScript {
227	type Error = BuilderError;
228
229	fn size(&self) -> usize {
230		var_size(self.script.len()) + self.script.len()
231	}
232
233	fn encode(&self, writer: &mut Encoder) {
234		writer.write_var_bytes(&self.script);
235	}
236
237	fn decode(reader: &mut Decoder) -> Result<Self, Self::Error> {
238		let script = reader.read_var_bytes()?;
239		Ok(Self { script })
240	}
241	fn to_array(&self) -> Vec<u8> {
242		let mut writer = Encoder::new();
243		self.encode(&mut writer);
244		writer.to_bytes()
245	}
246}
247
248#[cfg(test)]
249mod tests {
250	use hex_literal::hex;
251
252	use super::*;
253
254	#[test]
255	fn test_from_public_key() {
256		let key = "035fdb1d1f06759547020891ae97c729327853aeb1256b6fe0473bc2e9fa42ff50";
257		let pubkey = Secp256r1PublicKey::from_encoded(key.clone()).unwrap();
258		let script = VerificationScript::from_public_key(&pubkey);
259		let expected = format!(
260			"{}21{}{}{}",
261			OpCode::PushData1.to_hex_string(),
262			key,
263			OpCode::Syscall.to_hex_string(),
264			InteropService::SystemCryptoCheckSig.hash()
265		)
266		.from_hex_string()
267		.unwrap();
268
269		assert_eq!(script.script(), &expected);
270	}
271
272	#[test]
273	fn test_from_public_keys() {
274		let key1 =
275			hex!("035fdb1d1f06759547020891ae97c729327853aeb1256b6fe0473bc2e9fa42ff50").to_vec();
276		let key2 =
277			hex!("03eda286d19f7ee0b472afd1163d803d620a961e1581a8f2704b52c0285f6e022d").to_vec();
278		let key3 =
279			hex!("03ac81ec17f2f15fd6d193182f927c5971559c2a32b9408a06fec9e711fb7ca02e").to_vec();
280
281		let mut pubkeys = vec![
282			Secp256r1PublicKey::from(key1.clone()),
283			Secp256r1PublicKey::from(key2.clone()),
284			Secp256r1PublicKey::from(key3.clone()),
285		];
286
287		let script = VerificationScript::from_multi_sig(&mut pubkeys, 2);
288
289		let expected = format!(
290			"{}{}21{}{}21{}{}21{}{}{}{}",
291			OpCode::Push2.to_hex_string(),
292			OpCode::PushData1.to_hex_string(),
293			key1.to_hex_string(),
294			OpCode::PushData1.to_hex_string(),
295			key3.to_hex_string(),
296			OpCode::PushData1.to_hex_string(),
297			key2.to_hex_string(),
298			OpCode::Push3.to_hex_string(),
299			OpCode::Syscall.to_hex_string(),
300			InteropService::SystemCryptoCheckMultiSig.hash()
301		)
302		.from_hex_string()
303		.unwrap();
304
305		assert_eq!(script.script(), &expected);
306	}
307
308	#[test]
309	fn test_serialize_deserialize() {
310		let key = "035fdb1d1f06759547020891ae97c729327853aeb1256b6fe0473bc2e9fa42ff50";
311		let pubkey = Secp256r1PublicKey::from_encoded(key.clone()).unwrap();
312
313		let script = VerificationScript::from_public_key(&pubkey);
314
315		let expected = format!(
316			"{}21{}{}{}",
317			OpCode::PushData1.to_hex_string(),
318			key,
319			OpCode::Syscall.to_hex_string(),
320			InteropService::SystemCryptoCheckSig.hash()
321		);
322
323		let serialized = script.to_array();
324
325		// Manually deserialize
326		let deserialized = VerificationScript::from(serialized[1..].to_vec());
327
328		// Check deserialized script matches
329		assert_eq!(deserialized.script(), &expected.from_hex_string().unwrap());
330	}
331
332	#[test]
333	fn test_get_signing_threshold() {
334		// let key = hex!("...").to_vec();
335		//
336		// let script = VerificationScript::from(key);
337		// assert_eq!(script.get_signing_threshold(), 2);
338		//
339		// let script = VerificationScript::from(long_script);
340		// assert_eq!(script.get_signing_threshold(), 127);
341	}
342
343	#[test]
344	fn test_invalid_script() {
345		let script = VerificationScript::from(hex!("0123456789abcdef").to_vec());
346
347		assert!(script.get_signing_threshold().is_err());
348		assert!(script.get_public_keys().is_err());
349		assert!(script.get_nr_of_accounts().is_err());
350	}
351
352	#[test]
353	fn test_is_single_sig_script() -> Result<(), BuilderError> {
354		let script = format!(
355			"{}2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef{}{}",
356			OpCode::PushData1.to_hex_string(),
357			OpCode::Syscall.to_hex_string(),
358			InteropService::SystemCryptoCheckSig.hash()
359		);
360
361		let verification =
362			VerificationScript::from(hex::decode(&script).map_err(|e| {
363				BuilderError::InvalidScript(format!("Failed to decode hex: {}", e))
364			})?);
365		assert!(verification.is_single_sig());
366
367		Ok(())
368	}
369
370	#[test]
371	fn test_is_multi_sig() -> Result<(), BuilderError> {
372		let script = format!(
373			"{}{}{}{}{}{}{}{}{}{}",
374			OpCode::Push2.to_hex_string(),
375			OpCode::PushData1.to_hex_string(),
376			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
377			OpCode::PushData1.to_hex_string(),
378			"21031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
379			OpCode::PushData1.to_hex_string(),
380			"2103f0f9b358dfed564e74ffe242713f8bc866414226649f59859b140a130818898b",
381			OpCode::Push3.to_hex_string(),
382			OpCode::Syscall.to_hex_string(),
383			InteropService::SystemCryptoCheckMultiSig.hash()
384		);
385
386		let verification =
387			VerificationScript::from(hex::decode(&script).map_err(|e| {
388				BuilderError::InvalidScript(format!("Failed to decode hex: {}", e))
389			})?);
390		assert!(verification.is_multi_sig());
391
392		Ok(())
393	}
394
395	#[test]
396	fn test_fail_is_multi_sig_too_short() -> Result<(), BuilderError> {
397		let script = hex::decode("a89429c3be9f")
398			.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
399		let verification = VerificationScript::from(script);
400		assert!(!verification.is_multi_sig());
401
402		Ok(())
403	}
404
405	#[test]
406	fn test_fail_is_multi_sig_n_less_than_one() -> Result<(), BuilderError> {
407		let script = format!(
408			"{}{}{}{}{}{}3073b3bb",
409			OpCode::Push0.to_hex_string(),
410			OpCode::PushData1.to_hex_string(),
411			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
412			OpCode::Push1.to_hex_string(),
413			OpCode::PushNull.to_hex_string(),
414			OpCode::Syscall.to_hex_string(),
415		);
416
417		let verification =
418			VerificationScript::from(hex::decode(&script).map_err(|e| {
419				BuilderError::InvalidScript(format!("Failed to decode hex: {}", e))
420			})?);
421		assert!(!verification.is_multi_sig());
422
423		Ok(())
424	}
425
426	#[test]
427	fn test_fail_is_multi_sig_abrupt_end() -> Result<(), BuilderError> {
428		let script = hex::decode(&format!(
429			"{}{}2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
430			OpCode::Push2.to_hex_string(),
431			OpCode::PushData1.to_hex_string(),
432		))
433		.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
434
435		let verification = VerificationScript::from(script);
436		assert!(!verification.is_multi_sig());
437
438		Ok(())
439	}
440
441	#[test]
442	fn test_fail_is_multi_sig_wrong_push_data() -> Result<(), BuilderError> {
443		let script = hex::decode(&format!(
444			"{}{}{}{}{}{}{}{}3073b3bb",
445			OpCode::Push2.to_hex_string(),
446			OpCode::PushData1.to_hex_string(),
447			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
448			OpCode::PushData1.to_hex_string(),
449			"43031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
450			OpCode::Push2.to_hex_string(),
451			OpCode::PushNull.to_hex_string(),
452			OpCode::Syscall.to_hex_string(),
453		))
454		.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
455
456		let verification = VerificationScript::from(script);
457		assert!(!verification.is_multi_sig());
458
459		Ok(())
460	}
461
462	#[test]
463	fn test_fail_is_multi_sig_n_greater_than_m() -> Result<(), BuilderError> {
464		let script = hex::decode(&format!(
465			"{}{}{}{}{}{}{}{}3073b3bb",
466			OpCode::Push3.to_hex_string(),
467			OpCode::PushData1.to_hex_string(),
468			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
469			OpCode::PushData1.to_hex_string(),
470			"21031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
471			OpCode::Push2.to_hex_string(),
472			OpCode::PushNull.to_hex_string(),
473			OpCode::Syscall.to_hex_string()
474		))
475		.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
476
477		let verification = VerificationScript::from(script);
478		assert!(!verification.is_multi_sig());
479
480		Ok(())
481	}
482
483	#[test]
484	fn test_fail_is_multi_sig_m_incorrect() -> Result<(), BuilderError> {
485		let script = hex::decode(&format!(
486			"{}{}{}{}{}{}{}{}3073b3bb",
487			OpCode::Push2.to_hex_string(),
488			OpCode::PushData1.to_hex_string(),
489			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
490			OpCode::PushData1.to_hex_string(),
491			"21031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
492			OpCode::Push3.to_hex_string(),
493			OpCode::PushNull.to_hex_string(),
494			OpCode::Syscall.to_hex_string()
495		))
496		.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
497
498		let verification = VerificationScript::from(script);
499		assert!(!verification.is_multi_sig());
500
501		Ok(())
502	}
503
504	#[test]
505	fn test_fail_is_multi_sig_missing_push_null() -> Result<(), BuilderError> {
506		let script = hex::decode(&format!(
507			"{}{}{}{}{}{}{}3073b3bb",
508			OpCode::Push2.to_hex_string(),
509			OpCode::PushData1.to_hex_string(),
510			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
511			OpCode::PushData1.to_hex_string(),
512			"21031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
513			OpCode::Push2.to_hex_string(),
514			OpCode::Syscall.to_hex_string()
515		))
516		.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
517
518		let verification = VerificationScript::from(script);
519		assert!(!verification.is_multi_sig());
520
521		Ok(())
522	}
523
524	#[test]
525	fn test_fail_is_multi_sig_missing_syscall() -> Result<(), BuilderError> {
526		let script = hex::decode(&format!(
527			"{}{}{}{}{}{}{}3073b3bb",
528			OpCode::Push2.to_hex_string(),
529			OpCode::PushData1.to_hex_string(),
530			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
531			OpCode::PushData1.to_hex_string(),
532			"21031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
533			OpCode::Push2.to_hex_string(),
534			OpCode::PushNull.to_hex_string()
535		))
536		.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
537
538		let verification = VerificationScript::from(script);
539		assert!(!verification.is_multi_sig());
540
541		Ok(())
542	}
543
544	#[test]
545	fn test_fail_is_multi_sig_wrong_interop_service() -> Result<(), BuilderError> {
546		let script = hex::decode(&format!(
547			"{}{}{}{}{}{}{}{}103ab300",
548			OpCode::Push2.to_hex_string(),
549			OpCode::PushData1.to_hex_string(),
550			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
551			OpCode::PushData1.to_hex_string(),
552			"21031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
553			OpCode::Push3.to_hex_string(),
554			OpCode::PushNull.to_hex_string(),
555			OpCode::Syscall.to_hex_string()
556		))
557		.map_err(|e| BuilderError::InvalidScript(format!("Failed to decode hex: {}", e)))?;
558
559		let verification = VerificationScript::from(script);
560		assert!(!verification.is_multi_sig());
561
562		Ok(())
563	}
564
565	#[test]
566	fn test_public_keys_from_single_sig() -> Result<(), BuilderError> {
567		let script = format!(
568			"{}{}{}{}",
569			OpCode::PushData1.to_hex_string(),
570			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
571			OpCode::Syscall.to_hex_string(),
572			InteropService::SystemCryptoCheckSig.hash()
573		);
574
575		let verification =
576			VerificationScript::from(hex::decode(&script).map_err(|e| {
577				BuilderError::InvalidScript(format!("Failed to decode hex: {}", e))
578			})?);
579
580		let keys = verification.get_public_keys().unwrap();
581
582		assert_eq!(keys.len(), 1);
583
584		let encoded = keys[0].get_encoded(true);
585
586		assert_eq!(
587			hex::encode(&encoded),
588			"02028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef"
589		);
590
591		Ok(())
592	}
593
594	#[test]
595	fn test_public_keys_from_multi_sig() -> Result<(), BuilderError> {
596		let script = format!(
597			"{}{}{}{}{}{}{}{}{}{}",
598			OpCode::Push2.to_hex_string(),
599			OpCode::PushData1.to_hex_string(),
600			"2102028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef",
601			OpCode::PushData1.to_hex_string(),
602			"21031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9",
603			OpCode::PushData1.to_hex_string(),
604			"2103f0f9b358dfed564e74ffe242713f8bc866414226649f59859b140a130818898b",
605			OpCode::Push3.to_hex_string(),
606			OpCode::Syscall.to_hex_string(),
607			InteropService::SystemCryptoCheckMultiSig.hash()
608		);
609
610		let verification =
611			VerificationScript::from(hex::decode(&script).map_err(|e| {
612				BuilderError::InvalidScript(format!("Failed to decode hex: {}", e))
613			})?);
614
615		let keys = verification.get_public_keys()?;
616
617		assert_eq!(keys.len(), 3);
618
619		let key1 = keys[0].get_encoded(true);
620		let key2 = keys[1].get_encoded(true);
621		let key3 = keys[2].get_encoded(true);
622
623		assert_eq!(
624			hex::encode(&key1),
625			"02028a99826edc0c97d18e22b6932373d908d323aa7f92656a77ec26e8861699ef"
626		);
627		assert_eq!(
628			hex::encode(&key2),
629			"031d8e1630ce640966967bc6d95223d21f44304133003140c3b52004dc981349c9"
630		);
631		assert_eq!(
632			hex::encode(&key3),
633			"03f0f9b358dfed564e74ffe242713f8bc866414226649f59859b140a130818898b"
634		);
635
636		Ok(())
637	}
638}