code wiki / (root) / nx_ecdsa_sig_der_384.nx

nx_ecdsa_sig_der_384.nx source

↩ module page · 117 lines · 3999 B

1// nx_ecdsa_sig_der_384.nx -- parse DER-encoded ECDSA-P384 signatures 2// into (r, s) U384 scalars. 3// 4// Parallel to nx_ecdsa_sig_der.nx (which targets U256 / P-256). The 5// DER shape is identical -- SEQUENCE { INTEGER r, INTEGER s } -- but 6// the magnitude width changes from 32 to 48 bytes: 7// - 48 bytes when leading bit is 0 8// - 49 bytes when leading bit is 1 (DER 0x00 sign prefix) 9// - fewer than 48 bytes when high bytes happen to be zero 10// 11// Public API: 12// nx_ecdsa_sig_parse_der_384(buf, len, out_r, out_s) -> verdict 13// 14// Sealed verdict enum mirrors nx_ecdsa_sig_der's; reuses the same 15// constants (NX_ECDSA_DER_*). 16// 17// Per Cardinals 9 (single-responsibility -- parse, not verify), 18// 12 (defensive at boundaries -- bounded reads), 23 (preamble 19// explains why 49-byte INTEGER is normal for P-384). 20// 21// license_tier: INDEPENDENT_REDERIVE 22// genealogy_id: international-research-sources/ietf/rfc_3279 + rfc_5480 + itu_t/x_690 23// lineage_id: nishi_ecdsa_sig_der_384_q10 24 25// nx_safety_envelope: 26// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 27// sil_target: SIL1 28// evidence: [bulk_applied_2026-05-20, ecdsa-sig-der-384-parse] 29// verdict: NOT_YET_EVALUATED 30 31import "nx_syscalls.nx" 32import "nx_u384.nx" 33import "nx_asn1.nx" 34import "nx_ecdsa_sig_der.nx" 35 36// Helper: load a 1-49 byte big-endian unsigned integer into a 37// 12-limb LE U384 buffer, zero-padding the high limbs as needed. 38// Strips a single leading 0x00 byte (the DER positive-prefix) when 39// len == 49. 40// 41// Returns 0 on success, NX_ECDSA_DER_LEN_TOO_BIG if len > 49, 42// or NX_ECDSA_DER_BAD_R if len <= 0. 43func ecdsa_int_load_384(out: *i64, bytes: *u8, off: i64, len: i64) -> i64 { 44 if len <= 0 { return NX_ECDSA_DER_BAD_R } 45 if len > 49 { return NX_ECDSA_DER_LEN_TOO_BIG } 46 47 var skip: i64 = 0 48 var elen: i64 = len 49 if len == 49 { 50 if (bytes[off] & 0xff) != 0 { return NX_ECDSA_DER_LEN_TOO_BIG } 51 skip = 1 52 elen = 48 53 } 54 55 u384_zero(out) 56 let padded: *u8 = sys_mmap(48) 57 var k: i64 = 0 58 while k < 48 { padded[k] = 0; k = k + 1 } 59 let pad_off: i64 = 48 - elen 60 k = 0 61 while k < elen { 62 padded[pad_off + k] = bytes[off + skip + k] 63 k = k + 1 64 } 65 u384_load_be(out, padded) 66 return 0 67} 68 69// Parse a DER-encoded ECDSA signature (SEQUENCE { INTEGER r, 70// INTEGER s }) into two 12-limb LE U384 buffers. 71// 72// Returns NX_ECDSA_DER_OK on success, or a non-OK verdict. 73func nx_ecdsa_sig_parse_der_384(buf: *u8, len: i64, 74 out_r: *i64, out_s: *i64) -> i64 { 75 let c_raw: *u8 = sys_mmap(32) 76 let c: *Asn1Cursor = c_raw as *Asn1Cursor 77 asn1_cursor_init(c, len) 78 79 let outer_len_p: *i64 = sys_mmap(16) as *i64 80 let rc1: i64 = asn1_expect_tag(buf, c, ASN1_SEQUENCE, outer_len_p) 81 if rc1 < 0 { return NX_ECDSA_DER_BAD_OUTER } 82 let outer_end: i64 = c.pos + *outer_len_p 83 if outer_end > len { return NX_ECDSA_DER_BAD_OUTER } 84 85 let r_len_p: *i64 = sys_mmap(16) as *i64 86 let rc2: i64 = asn1_expect_tag(buf, c, ASN1_INTEGER, r_len_p) 87 if rc2 < 0 { return NX_ECDSA_DER_BAD_R } 88 let r_off: i64 = c.pos 89 let r_len: i64 = *r_len_p 90 c.pos = c.pos + r_len 91 if c.pos > outer_end { return NX_ECDSA_DER_BAD_R } 92 93 let load_r: i64 = ecdsa_int_load_384(out_r, buf, r_off, r_len) 94 if load_r != 0 { return load_r } 95 96 let s_len_p: *i64 = sys_mmap(16) as *i64 97 let rc3: i64 = asn1_expect_tag(buf, c, ASN1_INTEGER, s_len_p) 98 if rc3 < 0 { return NX_ECDSA_DER_BAD_S } 99 let s_off: i64 = c.pos 100 let s_len: i64 = *s_len_p 101 c.pos = c.pos + s_len 102 if c.pos > outer_end { return NX_ECDSA_DER_BAD_S } 103 104 let load_s: i64 = ecdsa_int_load_384(out_s, buf, s_off, s_len) 105 if load_s != 0 { 106 if load_s == NX_ECDSA_DER_BAD_R { return NX_ECDSA_DER_BAD_S } 107 return load_s 108 } 109 110 if c.pos != outer_end { return NX_ECDSA_DER_TRAILING } 111 112 return NX_ECDSA_DER_OK 113} 114 115func main() -> i64 { 116 return 0 117}