1use crate::error::{Error, Result};
21use saorsa_pqc::api::sig::{ml_dsa_65, MlDsaPublicKey, MlDsaSignature, MlDsaVariant};
22use std::fs;
23use std::path::Path;
24use tracing::debug;
25
26pub const SIGNING_CONTEXT: &[u8] = b"ant-node-release-v1";
28
29pub const SIGNATURE_SIZE: usize = 3309;
31
32pub const PUBLIC_KEY_SIZE: usize = 1952;
34
35const RELEASE_SIGNING_KEY: &[u8] = &[
41 0x55, 0xed, 0xf3, 0xe1, 0xf8, 0xc6, 0xd3, 0xbf, 0x45, 0x89, 0x2c, 0x79, 0x6d, 0xdd, 0x23, 0x13,
42 0xbe, 0xad, 0xd9, 0xdf, 0x8e, 0x4f, 0xf4, 0x3c, 0xb8, 0x63, 0x28, 0x79, 0x6e, 0x34, 0x84, 0xd3,
43 0x7d, 0xfb, 0x1e, 0x10, 0x43, 0x43, 0x89, 0xe9, 0x21, 0xa1, 0x3c, 0xd4, 0xc0, 0x0b, 0x44, 0x5c,
44 0x23, 0x99, 0xbd, 0x20, 0xd7, 0xb0, 0xac, 0x58, 0x8e, 0xed, 0xa2, 0x5a, 0x71, 0xd6, 0x6c, 0xf8,
45 0x3f, 0xbe, 0x9c, 0x73, 0x6c, 0x3b, 0xc3, 0xb4, 0xc3, 0x77, 0x6d, 0x49, 0x92, 0x56, 0x6e, 0x84,
46 0x66, 0x28, 0x73, 0xe4, 0xc5, 0xbb, 0x32, 0xb4, 0x3a, 0x33, 0x6c, 0x33, 0x77, 0x54, 0xc8, 0xc0,
47 0x18, 0x71, 0x82, 0x6a, 0xf4, 0xf2, 0x10, 0xf4, 0xb7, 0xd1, 0x57, 0xc6, 0x1d, 0x36, 0xbb, 0x80,
48 0x2b, 0xaf, 0xbd, 0x52, 0xa6, 0xcc, 0xd5, 0xa1, 0x63, 0x34, 0x0c, 0xbb, 0xc3, 0x83, 0x4d, 0xfc,
49 0xeb, 0x8f, 0xf7, 0x28, 0x93, 0xcf, 0x67, 0x8c, 0x9c, 0xad, 0xc6, 0xf1, 0x0a, 0x95, 0x32, 0x7f,
50 0x2b, 0x2c, 0x6c, 0x65, 0x2f, 0x8f, 0x29, 0x5b, 0x47, 0x64, 0x43, 0x90, 0x33, 0x7f, 0x82, 0x3c,
51 0xe3, 0xec, 0x75, 0xdb, 0x3d, 0x6d, 0xe4, 0xc1, 0x42, 0x92, 0x80, 0x99, 0xdd, 0xd2, 0x10, 0xb4,
52 0x91, 0x3e, 0x7a, 0xf6, 0xed, 0xd8, 0xa5, 0x1f, 0xe4, 0x07, 0xf0, 0x7b, 0x7b, 0x5e, 0x8e, 0x12,
53 0xe6, 0x6e, 0x04, 0xe5, 0xa6, 0xf4, 0x24, 0x6a, 0x28, 0x18, 0x6b, 0x0a, 0x5a, 0x36, 0x5d, 0x46,
54 0xe2, 0x22, 0xd7, 0x67, 0x29, 0x7b, 0xb9, 0x8e, 0x88, 0xd9, 0x76, 0x58, 0xc9, 0x12, 0xdf, 0xb6,
55 0x97, 0x76, 0x21, 0xfa, 0xec, 0x6c, 0x67, 0xea, 0x63, 0xc8, 0x3b, 0xc3, 0xf6, 0x5c, 0xc0, 0x5e,
56 0xf8, 0x08, 0x82, 0x63, 0xfc, 0xf9, 0x24, 0x2a, 0xf5, 0x20, 0x8c, 0x3c, 0xb7, 0xa8, 0x84, 0x8d,
57 0x87, 0xd8, 0x03, 0x74, 0xc6, 0xb1, 0x32, 0x2b, 0xe8, 0xd9, 0x21, 0x86, 0xfb, 0x28, 0x13, 0x3b,
58 0xe9, 0x4d, 0x99, 0x8f, 0xa3, 0x5c, 0x8c, 0xe0, 0xc6, 0xf3, 0x9b, 0x25, 0xcc, 0x11, 0x48, 0x39,
59 0x50, 0x00, 0x3b, 0x0e, 0x1d, 0xb7, 0xd2, 0xca, 0x0f, 0x10, 0x08, 0xed, 0x65, 0xa6, 0x6f, 0xee,
60 0x66, 0xd7, 0x68, 0x48, 0x0d, 0x9a, 0x73, 0xdf, 0x1c, 0x00, 0xcc, 0xbe, 0x86, 0xa6, 0x4f, 0x15,
61 0x6b, 0xf3, 0x56, 0xbb, 0x0d, 0x93, 0xc3, 0x8d, 0xa8, 0x31, 0x84, 0x91, 0x13, 0x7b, 0x14, 0x10,
62 0x60, 0x59, 0x18, 0x16, 0x08, 0xfd, 0x2d, 0x4d, 0x0c, 0xb2, 0x8c, 0x94, 0x6f, 0x7d, 0x81, 0xe9,
63 0x43, 0x9f, 0xaa, 0x13, 0xc2, 0x03, 0xff, 0xe2, 0xa2, 0x06, 0x38, 0x3b, 0x9b, 0xce, 0x85, 0x23,
64 0x80, 0xea, 0xa9, 0x92, 0x2f, 0x29, 0x15, 0xba, 0x68, 0x33, 0x6a, 0x0d, 0xbe, 0x11, 0x87, 0x61,
65 0xf1, 0xd5, 0x59, 0x50, 0x70, 0x51, 0x91, 0x6d, 0x4a, 0x9e, 0x69, 0x7c, 0xdd, 0x23, 0x8f, 0xa6,
66 0x4e, 0xa6, 0x81, 0xe7, 0xbc, 0x62, 0x40, 0x7c, 0x0b, 0xc0, 0xa2, 0xe1, 0xf8, 0x66, 0xc1, 0x82,
67 0x4a, 0x72, 0xb3, 0xee, 0x45, 0x44, 0xc7, 0x7b, 0xb1, 0xce, 0xfd, 0x80, 0xa9, 0x20, 0x20, 0xe7,
68 0xad, 0xdf, 0x9a, 0xa2, 0x86, 0xf3, 0x64, 0x93, 0xb2, 0xc9, 0xb1, 0x56, 0x5d, 0x66, 0x67, 0x9c,
69 0x29, 0x23, 0x53, 0xc4, 0xc9, 0x85, 0xd1, 0xed, 0x84, 0x2b, 0xc4, 0xa9, 0x93, 0x1b, 0x8f, 0xd8,
70 0xff, 0x1e, 0x2d, 0xa8, 0x3c, 0x27, 0x6c, 0xa5, 0x23, 0x2a, 0x5e, 0xd0, 0xcf, 0x11, 0xe2, 0x03,
71 0x7b, 0xdb, 0xa0, 0x10, 0xde, 0x2e, 0xa9, 0x5b, 0x42, 0x77, 0xcf, 0xa4, 0xc8, 0xab, 0xbd, 0x67,
72 0xa8, 0x88, 0x7b, 0x51, 0xe4, 0x39, 0xeb, 0x3e, 0x4e, 0x8f, 0xf1, 0x18, 0x83, 0x43, 0x43, 0x7e,
73 0xd1, 0x58, 0x27, 0x60, 0x54, 0xd5, 0xa8, 0x30, 0x54, 0xa1, 0xd0, 0xdc, 0x94, 0xf0, 0x28, 0x8d,
74 0x9c, 0xe4, 0x94, 0x1a, 0xcc, 0x87, 0xf7, 0xce, 0x4c, 0x63, 0x0d, 0xd0, 0x6d, 0x45, 0x20, 0x90,
75 0x5c, 0x95, 0x3e, 0x3c, 0x2e, 0xd0, 0x35, 0x2c, 0x35, 0x49, 0x2c, 0x6a, 0x7e, 0x5d, 0x5d, 0xc8,
76 0xaf, 0xb2, 0x96, 0x0b, 0x88, 0xb9, 0x2b, 0x33, 0x82, 0xa4, 0xc3, 0x81, 0xd3, 0xb9, 0x7e, 0x17,
77 0xba, 0xa7, 0x57, 0x47, 0x4d, 0x33, 0x55, 0xeb, 0xa5, 0x51, 0xd7, 0xe7, 0xc9, 0x46, 0x95, 0x52,
78 0x72, 0xb3, 0xb7, 0x57, 0x9b, 0xf6, 0x57, 0xff, 0x9d, 0xc5, 0x93, 0x4b, 0x05, 0x48, 0x41, 0x81,
79 0x25, 0xfc, 0xd9, 0x9e, 0x56, 0x18, 0x36, 0x17, 0x74, 0x1f, 0x77, 0x41, 0x98, 0x3f, 0x9e, 0x20,
80 0x74, 0x3d, 0x4e, 0xe3, 0xa0, 0xa0, 0x6b, 0x64, 0x38, 0xd7, 0xf7, 0x8c, 0xef, 0x01, 0x68, 0x82,
81 0x53, 0x30, 0x0a, 0xb6, 0xd1, 0x81, 0xd1, 0x70, 0x3c, 0xea, 0x96, 0xd3, 0x89, 0x21, 0x0e, 0xbb,
82 0x5a, 0x80, 0x51, 0x99, 0xeb, 0xef, 0x06, 0x85, 0xae, 0x8a, 0xfd, 0x23, 0x5a, 0x91, 0x3c, 0xe1,
83 0x85, 0xed, 0xf5, 0xf0, 0x58, 0x88, 0xac, 0xd0, 0xe8, 0x83, 0xb6, 0x90, 0xf2, 0xe6, 0x76, 0x5c,
84 0xcf, 0xd8, 0xba, 0xba, 0x88, 0xec, 0x0b, 0xd3, 0x77, 0x66, 0x30, 0x6e, 0xcc, 0x84, 0x29, 0xd3,
85 0x5f, 0xdf, 0x6e, 0x5b, 0x7f, 0x9d, 0x97, 0xed, 0x25, 0x33, 0xc6, 0x93, 0x4e, 0x62, 0x62, 0x7e,
86 0x00, 0x35, 0x20, 0x68, 0x4e, 0x85, 0x4a, 0xc1, 0xe0, 0x20, 0x2f, 0x80, 0x11, 0x2f, 0x33, 0xac,
87 0xd3, 0x8d, 0x56, 0x71, 0xcc, 0xa6, 0xeb, 0xe1, 0x0e, 0x3f, 0xea, 0x46, 0x16, 0xc5, 0x5e, 0x84,
88 0xbd, 0xad, 0x7a, 0x7a, 0x4a, 0x8c, 0x73, 0x66, 0xaa, 0x3e, 0xdc, 0xbe, 0x65, 0xa6, 0x5a, 0xed,
89 0xc6, 0x32, 0xcb, 0xbb, 0x03, 0xb9, 0xfb, 0xf3, 0x7a, 0xdc, 0x71, 0x7b, 0x46, 0x86, 0x4d, 0x55,
90 0xeb, 0x70, 0x05, 0xc9, 0x82, 0x03, 0xdf, 0x22, 0xa4, 0xfd, 0x25, 0xb1, 0x37, 0x3b, 0x90, 0x80,
91 0x35, 0x45, 0xab, 0x66, 0x0e, 0x4c, 0xcf, 0x5f, 0x69, 0x2f, 0x7b, 0x09, 0x7d, 0x6a, 0xb1, 0x91,
92 0x0d, 0x7e, 0xb4, 0xd4, 0xcb, 0x5f, 0xa3, 0xf3, 0x00, 0x73, 0x03, 0xbf, 0xc9, 0x6e, 0x9c, 0x48,
93 0x9e, 0x1c, 0x3b, 0xb0, 0x1f, 0xab, 0xb6, 0xea, 0x72, 0x04, 0x9d, 0xec, 0x6c, 0xc9, 0xd2, 0xed,
94 0x6f, 0x72, 0x19, 0x5c, 0x3a, 0xfc, 0x57, 0x68, 0xf6, 0x05, 0x88, 0xd8, 0xe6, 0x38, 0xd4, 0xe0,
95 0x9c, 0xed, 0xa7, 0x38, 0xa9, 0xab, 0xd4, 0x79, 0xf0, 0x3e, 0x39, 0x32, 0xa3, 0x6b, 0x2a, 0x49,
96 0x53, 0x12, 0xaf, 0x7f, 0x6d, 0x26, 0xf6, 0x16, 0x8c, 0x9d, 0xac, 0x0d, 0xf7, 0x33, 0xf4, 0x69,
97 0xc9, 0x47, 0xec, 0xba, 0xac, 0x95, 0x7e, 0x7d, 0x41, 0xc0, 0xca, 0xce, 0xd5, 0xf8, 0x9e, 0x49,
98 0xe0, 0x4d, 0xaa, 0x13, 0xea, 0x05, 0x3a, 0xf2, 0x71, 0x3b, 0xad, 0x8b, 0x16, 0xd7, 0x12, 0x07,
99 0xea, 0xf6, 0x81, 0x09, 0x3f, 0x04, 0x20, 0x2f, 0xd5, 0x78, 0xd8, 0xc4, 0xee, 0xca, 0x9e, 0x43,
100 0xe1, 0x5b, 0xe4, 0x21, 0xaf, 0xeb, 0xbf, 0xf8, 0x8c, 0x52, 0x1f, 0x3f, 0xb8, 0x8f, 0x3c, 0xfa,
101 0x3c, 0x94, 0x81, 0x59, 0x53, 0x21, 0xd6, 0xf1, 0x3a, 0x9a, 0x7b, 0xd8, 0x18, 0xe9, 0xbd, 0x41,
102 0xc4, 0x4a, 0x5c, 0x8a, 0x21, 0x2e, 0xda, 0x70, 0x32, 0xb7, 0xef, 0x49, 0x88, 0x38, 0xe3, 0x8d,
103 0xd9, 0x53, 0xd1, 0xc2, 0x9c, 0xec, 0xf6, 0x76, 0x75, 0x0a, 0x31, 0x37, 0xba, 0xd2, 0xaa, 0x37,
104 0xce, 0x30, 0x7a, 0x2b, 0xdb, 0xce, 0x44, 0x86, 0x6c, 0x20, 0x1a, 0x6c, 0xae, 0x0a, 0x20, 0xbb,
105 0xfa, 0x6b, 0x04, 0x11, 0xdd, 0xfd, 0x89, 0x7a, 0xaf, 0x1f, 0x63, 0x85, 0x75, 0x78, 0x62, 0x77,
106 0xa0, 0x13, 0x8e, 0x4c, 0x5b, 0x11, 0x06, 0xcf, 0x97, 0x28, 0x2d, 0x9a, 0xd1, 0x5c, 0xcd, 0x3e,
107 0x0a, 0xc0, 0x42, 0x93, 0x60, 0xe2, 0x37, 0x1b, 0xf5, 0x68, 0x72, 0xd6, 0x8b, 0xd1, 0x78, 0xe4,
108 0x1a, 0xa5, 0xbc, 0x7f, 0xd2, 0x6e, 0xfd, 0x3e, 0xdd, 0xca, 0x6f, 0x32, 0x7b, 0x19, 0x39, 0x48,
109 0x88, 0x31, 0x10, 0x7f, 0xa6, 0x4d, 0xc9, 0xe3, 0x1d, 0x40, 0xe1, 0x11, 0xfc, 0xbc, 0x32, 0xa9,
110 0x06, 0xde, 0x17, 0x29, 0x14, 0x50, 0x83, 0xdb, 0x54, 0x2c, 0x9e, 0x75, 0x4e, 0xf7, 0xee, 0xc4,
111 0x8d, 0xc2, 0xf3, 0xf8, 0x03, 0x02, 0x0e, 0x4e, 0xc4, 0x42, 0xef, 0x5b, 0x3b, 0x37, 0x52, 0x2e,
112 0x51, 0xf3, 0x72, 0x18, 0x32, 0x48, 0x42, 0xbe, 0xdf, 0xe2, 0x46, 0x49, 0x17, 0x77, 0xe4, 0x4e,
113 0x5f, 0xda, 0x50, 0xda, 0xce, 0x30, 0x65, 0x3a, 0xf9, 0xef, 0xd4, 0x8b, 0x91, 0x88, 0xbb, 0xb9,
114 0x69, 0x65, 0xaa, 0x3b, 0xe1, 0xd5, 0xf8, 0x0a, 0x2a, 0x8a, 0xc9, 0x67, 0x54, 0xd8, 0x54, 0x55,
115 0x3e, 0xac, 0x9e, 0x9d, 0x73, 0x6a, 0x1f, 0x21, 0xe1, 0x2b, 0xaa, 0x87, 0x16, 0x40, 0xfc, 0x37,
116 0xd8, 0xa9, 0xbc, 0x39, 0x72, 0x78, 0xfc, 0x9d, 0x6d, 0xe2, 0xd8, 0x5d, 0x30, 0xbb, 0xd4, 0x9b,
117 0xbd, 0xf3, 0xeb, 0x64, 0x78, 0x4a, 0x63, 0x33, 0xe9, 0x95, 0x9c, 0xac, 0x94, 0xc1, 0xf8, 0xd9,
118 0x2c, 0x25, 0x46, 0x92, 0x1a, 0xa5, 0x77, 0xca, 0x02, 0xaf, 0x97, 0x49, 0x24, 0x2f, 0xe6, 0x77,
119 0x3a, 0x3d, 0x35, 0x05, 0x08, 0xd9, 0x90, 0x74, 0xb2, 0x28, 0x6e, 0xbd, 0x34, 0x85, 0xd5, 0x47,
120 0x88, 0x5d, 0x36, 0xe8, 0x8c, 0xd1, 0x9b, 0x5d, 0x49, 0xa8, 0x94, 0x46, 0x22, 0xbd, 0x67, 0x19,
121 0x77, 0x8f, 0xb7, 0xda, 0x17, 0x68, 0x49, 0xf0, 0xf5, 0x6d, 0x2a, 0xe4, 0x9b, 0x4c, 0x07, 0xac,
122 0x91, 0xa6, 0x2d, 0x41, 0x6f, 0xf6, 0x40, 0xa7, 0xe9, 0xc4, 0x3e, 0x7c, 0xc3, 0xb6, 0x8b, 0xf5,
123 0x0a, 0x47, 0x19, 0xd4, 0x86, 0x16, 0x40, 0x02, 0x5a, 0x9b, 0x6f, 0xe0, 0x83, 0x9b, 0x84, 0x61,
124 0x28, 0x35, 0xdb, 0xa6, 0x22, 0xae, 0x67, 0x0c, 0x72, 0x5f, 0xd0, 0xdc, 0x9c, 0x8b, 0xca, 0xa5,
125 0xc7, 0xed, 0x5c, 0xe0, 0xba, 0xe7, 0x57, 0xbb, 0xf3, 0xc2, 0xa4, 0x21, 0x16, 0x11, 0xe9, 0x5e,
126 0x47, 0xdd, 0xb5, 0x88, 0x9c, 0x6a, 0x2c, 0xcc, 0x6b, 0x2c, 0x19, 0xbc, 0x52, 0x3f, 0xf5, 0x51,
127 0x15, 0xcd, 0xae, 0x61, 0x1f, 0xca, 0x16, 0xfb, 0xd8, 0xd7, 0x20, 0x2f, 0xe4, 0xb9, 0xd4, 0x9a,
128 0x8b, 0xf7, 0xa5, 0x03, 0x5d, 0x6b, 0xde, 0x57, 0x69, 0xef, 0x50, 0xff, 0xed, 0x2d, 0x41, 0x4f,
129 0x5c, 0x87, 0x7a, 0x04, 0xce, 0x91, 0xf0, 0x23, 0x14, 0x20, 0x54, 0xae, 0x25, 0x6a, 0xea, 0x71,
130 0xd2, 0x5c, 0x26, 0x3b, 0xc9, 0x75, 0xe4, 0x68, 0x92, 0x66, 0x63, 0x03, 0xa0, 0xf6, 0x9c, 0x46,
131 0x48, 0x89, 0xe0, 0xad, 0x10, 0x4f, 0x35, 0x6f, 0x68, 0xb9, 0x63, 0xd0, 0x9c, 0xa6, 0xa6, 0x0e,
132 0x93, 0x95, 0x63, 0xda, 0xea, 0x26, 0x27, 0xab, 0x10, 0x67, 0x6d, 0xe8, 0xc8, 0x4e, 0xc9, 0x9b,
133 0x53, 0x96, 0xa8, 0x6f, 0x77, 0x71, 0x37, 0xef, 0xf6, 0x52, 0x51, 0x94, 0x7a, 0x3b, 0x8e, 0xf2,
134 0x4c, 0x14, 0x21, 0x59, 0xc5, 0xe9, 0x85, 0x1a, 0xba, 0xf2, 0x98, 0xaf, 0x80, 0x01, 0xc4, 0x57,
135 0x78, 0xde, 0x44, 0xa9, 0x0e, 0xc5, 0x31, 0x88, 0xe0, 0x65, 0x56, 0x8c, 0x16, 0xdb, 0x80, 0x89,
136 0x63, 0xd5, 0xc2, 0x91, 0x7d, 0x90, 0x89, 0x7b, 0xfa, 0xa0, 0x2a, 0x55, 0xcc, 0x62, 0x20, 0xcb,
137 0xcf, 0x89, 0x28, 0x8b, 0xa5, 0x70, 0x55, 0x69, 0x76, 0x30, 0xb0, 0xf0, 0x7e, 0x30, 0x64, 0x4c,
138 0x7b, 0x4b, 0x41, 0xcf, 0x6f, 0x28, 0x8b, 0x99, 0x5f, 0x8a, 0xab, 0xf5, 0xfb, 0x45, 0xb6, 0xcd,
139 0xca, 0xc9, 0x87, 0xb0, 0x83, 0x3e, 0xe3, 0x18, 0xce, 0xab, 0x6b, 0xd7, 0x57, 0x84, 0xd6, 0x43,
140 0x1c, 0x10, 0xc2, 0xf2, 0x8b, 0xb4, 0xd2, 0xab, 0xd1, 0xca, 0x73, 0xc6, 0xc0, 0x72, 0xa7, 0x69,
141 0x74, 0x02, 0x73, 0xf6, 0xa3, 0xe3, 0x9b, 0x6d, 0xc9, 0x01, 0x16, 0x95, 0x78, 0x9e, 0x17, 0x73,
142 0x39, 0xca, 0x0a, 0xab, 0x03, 0x7c, 0x3b, 0xe9, 0x41, 0x69, 0x71, 0x47, 0xba, 0xc4, 0xc1, 0x34,
143 0x9f, 0x47, 0x2b, 0xf2, 0x8e, 0x01, 0xf0, 0xe2, 0x86, 0x18, 0xb1, 0x80, 0x46, 0x06, 0x61, 0x42,
144 0xd8, 0x25, 0x41, 0xe1, 0xd7, 0x17, 0x8b, 0xa3, 0x1f, 0x64, 0x91, 0x1f, 0x28, 0x82, 0x1a, 0x63,
145 0x11, 0x68, 0xa7, 0x0f, 0x9a, 0x8c, 0xaf, 0x61, 0x18, 0x98, 0x31, 0x3a, 0x95, 0xe4, 0xf4, 0x73,
146 0x8b, 0xf5, 0xb2, 0x1c, 0x19, 0xcb, 0x22, 0x77, 0x23, 0x07, 0x85, 0x80, 0xc9, 0x1c, 0x74, 0xee,
147 0xbf, 0x97, 0x97, 0x60, 0x17, 0x29, 0x2a, 0x4c, 0x50, 0x64, 0x7e, 0xa0, 0x99, 0x13, 0x86, 0xa6,
148 0x89, 0x3c, 0xd6, 0xd8, 0x9c, 0xef, 0x24, 0xe6, 0x92, 0xe9, 0x58, 0xc6, 0x38, 0x61, 0x86, 0x39,
149 0xcf, 0xbe, 0x70, 0xf6, 0x5a, 0x69, 0x80, 0x6e, 0x80, 0xcb, 0x14, 0x6f, 0x9a, 0x26, 0x30, 0x28,
150 0x3d, 0x32, 0x07, 0x41, 0x24, 0x9c, 0x84, 0xba, 0x4a, 0x67, 0x5f, 0xf0, 0x17, 0x28, 0x23, 0xfe,
151 0x39, 0x39, 0x80, 0xb5, 0xac, 0x28, 0x53, 0x97, 0xdd, 0x0d, 0x5b, 0x55, 0xd4, 0x22, 0x81, 0x81,
152 0x4d, 0xb4, 0x8b, 0x2b, 0x33, 0xad, 0x62, 0xd5, 0x8d, 0xfe, 0x39, 0xd4, 0xd8, 0xf1, 0x5d, 0x0f,
153 0x19, 0x64, 0xbf, 0xac, 0x91, 0xf1, 0x92, 0x3c, 0x7f, 0x3a, 0xb8, 0xa6, 0xb5, 0xd7, 0x3a, 0x36,
154 0xc8, 0x9c, 0x65, 0x1b, 0xa6, 0x2a, 0x98, 0x15, 0x96, 0x23, 0xd4, 0xe3, 0xa6, 0x07, 0x23, 0xa9,
155 0xce, 0x16, 0x50, 0xb1, 0x97, 0xce, 0x69, 0x00, 0x68, 0x1a, 0xf8, 0x71, 0x88, 0x55, 0x5e, 0xf1,
156 0xd9, 0x81, 0x64, 0x1c, 0x95, 0x2b, 0x68, 0xf9, 0xbe, 0x78, 0x9a, 0xbb, 0xf9, 0x2c, 0x7f, 0x6e,
157 0xed, 0x66, 0xfd, 0x44, 0xaa, 0xfe, 0x96, 0x84, 0xde, 0xbc, 0x47, 0x78, 0xc4, 0x90, 0xb8, 0xe4,
158 0xde, 0xb8, 0x3f, 0xaf, 0xc5, 0x05, 0xe6, 0x6e, 0x62, 0x4c, 0x43, 0x07, 0xbf, 0x06, 0x99, 0xf3,
159 0x18, 0x38, 0x26, 0x3f, 0x87, 0xd7, 0x04, 0x0e, 0xa0, 0x0d, 0xbd, 0xf8, 0xda, 0x50, 0x24, 0xe9,
160 0x46, 0x28, 0xbe, 0x70, 0x7f, 0x79, 0x25, 0xd1, 0x1a, 0xe6, 0x5e, 0x74, 0xe5, 0x2f, 0x5d, 0xd2,
161 0xc2, 0x60, 0xe9, 0x6e, 0x15, 0x4c, 0x70, 0x40, 0x99, 0x88, 0xe0, 0x93, 0xfe, 0x36, 0x1e, 0x64,
162 0x14, 0xa5, 0xcf, 0x35, 0xf2, 0xd2, 0xab, 0x8d, 0xf4, 0x1d, 0x29, 0xbd, 0xac, 0x08, 0xaf, 0xd6,
163];
164
165pub fn verify_binary_signature(binary_path: &Path, signature: &[u8]) -> Result<()> {
179 let public_key = MlDsaPublicKey::from_bytes(MlDsaVariant::MlDsa65, RELEASE_SIGNING_KEY)
180 .map_err(|e| Error::Crypto(format!("Invalid release key: {e}")))?;
181
182 verify_binary_signature_with_key(binary_path, signature, &public_key)
183}
184
185pub fn verify_binary_signature_with_key(
204 binary_path: &Path,
205 signature: &[u8],
206 public_key: &MlDsaPublicKey,
207) -> Result<()> {
208 debug!("Verifying signature for: {}", binary_path.display());
209
210 let binary_content = fs::read(binary_path).map_err(|e| {
212 Error::Crypto(format!(
213 "Failed to read binary '{}': {e}",
214 binary_path.display()
215 ))
216 })?;
217
218 if signature.len() != SIGNATURE_SIZE {
220 return Err(Error::Crypto(format!(
221 "Invalid signature size: expected {SIGNATURE_SIZE}, got {}",
222 signature.len()
223 )));
224 }
225
226 let sig = MlDsaSignature::from_bytes(MlDsaVariant::MlDsa65, signature)
228 .map_err(|e| Error::Crypto(format!("Invalid signature format: {e}")))?;
229
230 let dsa = ml_dsa_65();
232 let valid = dsa
233 .verify_with_context(public_key, &binary_content, &sig, SIGNING_CONTEXT)
234 .map_err(|e| Error::Crypto(format!("Signature verification error: {e}")))?;
235
236 if valid {
237 debug!("Signature verified successfully");
238 Ok(())
239 } else {
240 Err(Error::Crypto(
241 "Signature verification failed: invalid signature".to_string(),
242 ))
243 }
244}
245
246pub fn verify_from_file(binary_path: &Path, signature_path: &Path) -> Result<()> {
257 debug!(
258 "Verifying {} with signature from {}",
259 binary_path.display(),
260 signature_path.display()
261 );
262
263 let signature = fs::read(signature_path)?;
264 verify_binary_signature(binary_path, &signature)
265}
266
267pub fn verify_from_file_with_key(
279 binary_path: &Path,
280 signature_path: &Path,
281 public_key: &MlDsaPublicKey,
282) -> Result<()> {
283 debug!(
284 "Verifying {} with signature from {}",
285 binary_path.display(),
286 signature_path.display()
287 );
288
289 let signature = fs::read(signature_path)?;
290 verify_binary_signature_with_key(binary_path, &signature, public_key)
291}
292
293#[cfg(test)]
294#[allow(
295 clippy::unwrap_used,
296 clippy::expect_used,
297 clippy::cast_possible_truncation,
298 clippy::cast_sign_loss
299)]
300mod tests {
301 use super::*;
302 use saorsa_pqc::api::sig::ml_dsa_65;
303 use std::io::Write;
304 use tempfile::NamedTempFile;
305
306 #[test]
308 fn test_verify_valid_signature() {
309 let dsa = ml_dsa_65();
310 let (public_key, secret_key) = dsa.generate_keypair().unwrap();
311 let binary_content = b"test binary content for signing";
312
313 let mut file = NamedTempFile::new().unwrap();
314 file.write_all(binary_content).unwrap();
315
316 let signature = dsa
317 .sign_with_context(&secret_key, binary_content, SIGNING_CONTEXT)
318 .unwrap();
319
320 let result =
321 verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
322 assert!(result.is_ok(), "Valid signature should verify: {result:?}");
323 }
324
325 #[test]
327 fn test_reject_invalid_signature() {
328 let dsa = ml_dsa_65();
329 let (public_key, _) = dsa.generate_keypair().unwrap();
330 let binary_content = b"test binary content";
331
332 let mut file = NamedTempFile::new().unwrap();
333 file.write_all(binary_content).unwrap();
334
335 let invalid_sig = vec![0u8; SIGNATURE_SIZE];
337
338 let result = verify_binary_signature_with_key(file.path(), &invalid_sig, &public_key);
339 assert!(result.is_err(), "Invalid signature should be rejected");
340 }
341
342 #[test]
344 fn test_reject_wrong_key() {
345 let dsa = ml_dsa_65();
346 let (_, secret_key) = dsa.generate_keypair().unwrap();
347 let (wrong_key, _) = dsa.generate_keypair().unwrap();
348 let binary_content = b"test binary content";
349
350 let mut file = NamedTempFile::new().unwrap();
351 file.write_all(binary_content).unwrap();
352
353 let signature = dsa
354 .sign_with_context(&secret_key, binary_content, SIGNING_CONTEXT)
355 .unwrap();
356
357 let result =
358 verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &wrong_key);
359 assert!(result.is_err(), "Wrong key should fail verification");
360 }
361
362 #[test]
364 fn test_reject_modified_binary() {
365 let dsa = ml_dsa_65();
366 let (public_key, secret_key) = dsa.generate_keypair().unwrap();
367 let original_content = b"original binary content";
368
369 let signature = dsa
371 .sign_with_context(&secret_key, original_content, SIGNING_CONTEXT)
372 .unwrap();
373
374 let mut file = NamedTempFile::new().unwrap();
376 file.write_all(b"MODIFIED binary content").unwrap();
377
378 let result =
379 verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
380 assert!(result.is_err(), "Modified binary should fail verification");
381 }
382
383 #[test]
385 fn test_reject_malformed_signature() {
386 let dsa = ml_dsa_65();
387 let (public_key, _) = dsa.generate_keypair().unwrap();
388 let binary_content = b"test content";
389
390 let mut file = NamedTempFile::new().unwrap();
391 file.write_all(binary_content).unwrap();
392
393 let short_sig = vec![0u8; 100];
395
396 let result = verify_binary_signature_with_key(file.path(), &short_sig, &public_key);
397 assert!(result.is_err(), "Malformed signature should be rejected");
398 assert!(
399 result
400 .unwrap_err()
401 .to_string()
402 .contains("Invalid signature size"),
403 "Error should mention invalid size"
404 );
405 }
406
407 #[test]
409 fn test_empty_file() {
410 let dsa = ml_dsa_65();
411 let (public_key, secret_key) = dsa.generate_keypair().unwrap();
412 let empty_content: &[u8] = b"";
413
414 let mut file = NamedTempFile::new().unwrap();
415 file.write_all(empty_content).unwrap();
416
417 let signature = dsa
418 .sign_with_context(&secret_key, empty_content, SIGNING_CONTEXT)
419 .unwrap();
420
421 let result =
422 verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
423 assert!(result.is_ok(), "Empty file should verify: {result:?}");
424 }
425
426 #[test]
428 fn test_nonexistent_file() {
429 let dsa = ml_dsa_65();
430 let (public_key, _) = dsa.generate_keypair().unwrap();
431 let path = Path::new("/nonexistent/path/to/binary");
432 let sig = vec![0u8; SIGNATURE_SIZE];
433
434 let result = verify_binary_signature_with_key(path, &sig, &public_key);
435 assert!(result.is_err(), "Non-existent file should fail");
436 }
437
438 #[test]
440 fn test_wrong_context_rejected() {
441 let dsa = ml_dsa_65();
442 let (public_key, secret_key) = dsa.generate_keypair().unwrap();
443 let content = b"binary content";
444
445 let mut file = NamedTempFile::new().unwrap();
446 file.write_all(content).unwrap();
447
448 let signature = dsa
450 .sign_with_context(&secret_key, content, b"wrong-context-string")
451 .unwrap();
452
453 let result =
455 verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
456 assert!(
457 result.is_err(),
458 "Wrong context should fail verification: {result:?}"
459 );
460 }
461
462 #[test]
464 fn test_verify_from_sig_file() {
465 let dsa = ml_dsa_65();
466 let (public_key, secret_key) = dsa.generate_keypair().unwrap();
467 let content = b"binary content for sig file test";
468
469 let mut binary_file = NamedTempFile::new().unwrap();
470 binary_file.write_all(content).unwrap();
471
472 let signature = dsa
473 .sign_with_context(&secret_key, content, SIGNING_CONTEXT)
474 .unwrap();
475
476 let mut sig_file = NamedTempFile::new().unwrap();
477 sig_file.write_all(&signature.to_bytes()).unwrap();
478
479 let result = verify_from_file_with_key(binary_file.path(), sig_file.path(), &public_key);
480 assert!(
481 result.is_ok(),
482 "Detached sig file verification should succeed: {result:?}"
483 );
484 }
485
486 #[test]
488 fn test_large_binary() {
489 let dsa = ml_dsa_65();
490 let (public_key, secret_key) = dsa.generate_keypair().unwrap();
491
492 let large_content: Vec<u8> = (0..1_000_000).map(|i| (i % 256) as u8).collect();
494
495 let mut file = NamedTempFile::new().unwrap();
496 file.write_all(&large_content).unwrap();
497
498 let signature = dsa
499 .sign_with_context(&secret_key, &large_content, SIGNING_CONTEXT)
500 .unwrap();
501
502 let result =
503 verify_binary_signature_with_key(file.path(), &signature.to_bytes(), &public_key);
504 assert!(result.is_ok(), "Large binary should verify: {result:?}");
505 }
506
507 #[test]
509 fn test_release_key_configured() {
510 assert_eq!(
512 RELEASE_SIGNING_KEY.len(),
513 PUBLIC_KEY_SIZE,
514 "Embedded release key should be {PUBLIC_KEY_SIZE} bytes"
515 );
516
517 let result = MlDsaPublicKey::from_bytes(MlDsaVariant::MlDsa65, RELEASE_SIGNING_KEY);
519 assert!(
520 result.is_ok(),
521 "Embedded release key should be valid ML-DSA-65 public key"
522 );
523 }
524
525 #[test]
527 fn test_embedded_key_rejects_invalid_signature() {
528 let content = b"test binary content";
529
530 let mut file = NamedTempFile::new().unwrap();
531 file.write_all(content).unwrap();
532
533 let invalid_sig = vec![0u8; SIGNATURE_SIZE];
535
536 let result = verify_binary_signature(file.path(), &invalid_sig);
537 assert!(result.is_err(), "Invalid signature should be rejected");
538 }
539}