1use crate::asn1::oid::{ID_EC_PUBLIC_KEY, SM2P256V1};
29use crate::asn1::{reader, writer};
30use crate::sec1::{SEC1_UNCOMPRESSED_LEN, decode_uncompressed_point, encode_uncompressed_point};
31use crate::sm2::point::ProjectivePoint;
32use alloc::vec::Vec;
33
34#[must_use]
46#[allow(clippy::missing_panics_doc)]
47pub fn encode(point: &ProjectivePoint) -> Vec<u8> {
48 let (x, y) = point.to_affine().expect("SPKI: point at infinity");
49 let pk = encode_uncompressed_point(&x, &y);
50 encode_uncompressed(&pk)
51}
52
53#[must_use]
57pub fn encode_uncompressed(uncompressed: &[u8; SEC1_UNCOMPRESSED_LEN]) -> Vec<u8> {
58 let mut alg_inner = Vec::with_capacity(ID_EC_PUBLIC_KEY.len() + SM2P256V1.len() + 4);
60 writer::write_oid(&mut alg_inner, ID_EC_PUBLIC_KEY);
61 writer::write_oid(&mut alg_inner, SM2P256V1);
62
63 let mut alg_seq = Vec::with_capacity(alg_inner.len() + 4);
64 writer::write_sequence(&mut alg_seq, &alg_inner);
65
66 let mut bitstr = Vec::with_capacity(uncompressed.len() + 4);
68 writer::write_bit_string(&mut bitstr, 0, uncompressed);
69
70 let mut body = Vec::with_capacity(alg_seq.len() + bitstr.len());
71 body.extend_from_slice(&alg_seq);
72 body.extend_from_slice(&bitstr);
73
74 let mut out = Vec::with_capacity(body.len() + 4);
75 writer::write_sequence(&mut out, &body);
76 out
77}
78
79#[must_use]
93pub fn decode(input: &[u8]) -> Option<ProjectivePoint> {
94 let (body, rest) = reader::read_sequence(input)?;
95 if !rest.is_empty() {
96 return None;
97 }
98
99 let (alg_inner, body) = reader::read_sequence(body)?;
101 let (alg_oid, alg_inner) = reader::read_oid(alg_inner)?;
102 if alg_oid != ID_EC_PUBLIC_KEY {
103 return None;
104 }
105 let (curve_oid, alg_inner) = reader::read_oid(alg_inner)?;
107 if curve_oid != SM2P256V1 || !alg_inner.is_empty() {
108 return None;
109 }
110
111 let (unused, pk_bytes, body) = reader::read_bit_string(body)?;
113 if unused != 0 || !body.is_empty() {
114 return None;
115 }
116 decode_uncompressed_point(pk_bytes)
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
125 fn round_trip_generator() {
126 let g = ProjectivePoint::generator();
127 let der = encode(&g);
128 let recovered = decode(&der).expect("decode");
129 let (gx, gy) = g.to_affine().expect("G finite");
130 let (rx, ry) = recovered.to_affine().expect("recovered finite");
131 assert_eq!(rx.retrieve(), gx.retrieve());
132 assert_eq!(ry.retrieve(), gy.retrieve());
133 }
134
135 #[test]
138 fn encoded_form_shape() {
139 let g = ProjectivePoint::generator();
140 let der = encode(&g);
141 assert_eq!(der[0], 0x30, "outer tag must be SEQUENCE");
142 assert_eq!(der.len(), 91, "SM2 SPKI is 91 bytes");
146 }
147
148 #[test]
149 fn rejects_wrong_algorithm_oid() {
150 let mut alg_inner = Vec::new();
153 writer::write_oid(
154 &mut alg_inner,
155 &[0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01],
156 );
157 writer::write_null(&mut alg_inner);
158 let mut alg_seq = Vec::new();
159 writer::write_sequence(&mut alg_seq, &alg_inner);
160 let mut bitstr = Vec::new();
161 writer::write_bit_string(&mut bitstr, 0, &[0u8; 65]);
162 let mut body = Vec::new();
163 body.extend_from_slice(&alg_seq);
164 body.extend_from_slice(&bitstr);
165 let mut der = Vec::new();
166 writer::write_sequence(&mut der, &body);
167 assert!(decode(&der).is_none());
168 }
169
170 #[test]
171 fn rejects_wrong_curve_oid() {
172 let mut alg_inner = Vec::new();
174 writer::write_oid(&mut alg_inner, ID_EC_PUBLIC_KEY);
175 writer::write_oid(
176 &mut alg_inner,
177 &[0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07],
178 );
179 let mut alg_seq = Vec::new();
180 writer::write_sequence(&mut alg_seq, &alg_inner);
181 let mut bitstr = Vec::new();
182 writer::write_bit_string(&mut bitstr, 0, &[0u8; 65]);
183 let mut body = Vec::new();
184 body.extend_from_slice(&alg_seq);
185 body.extend_from_slice(&bitstr);
186 let mut der = Vec::new();
187 writer::write_sequence(&mut der, &body);
188 assert!(decode(&der).is_none());
189 }
190
191 #[test]
192 fn rejects_off_curve_point() {
193 let mut alg_inner = Vec::new();
194 writer::write_oid(&mut alg_inner, ID_EC_PUBLIC_KEY);
195 writer::write_oid(&mut alg_inner, SM2P256V1);
196 let mut alg_seq = Vec::new();
197 writer::write_sequence(&mut alg_seq, &alg_inner);
198 let mut pt = [0u8; 65];
199 pt[0] = 0x04;
200 pt[1] = 1;
201 pt[33] = 1; let mut bitstr = Vec::new();
203 writer::write_bit_string(&mut bitstr, 0, &pt);
204 let mut body = Vec::new();
205 body.extend_from_slice(&alg_seq);
206 body.extend_from_slice(&bitstr);
207 let mut der = Vec::new();
208 writer::write_sequence(&mut der, &body);
209 assert!(decode(&der).is_none());
210 }
211
212 #[test]
213 fn rejects_trailing_bytes() {
214 let g = ProjectivePoint::generator();
215 let mut der = encode(&g);
216 der.push(0x00);
217 assert!(decode(&der).is_none());
218 }
219}