github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/sig64/sigcompress.go (about)

     1  package sig64
     2  
     3  import "fmt"
     4  
     5  // signatures are like 71 or 70 bytes, variable length... this really bugs me!
     6  // But I've lived with it.  But with this, the (txid, sig) pair is slightly over
     7  // 100 bytes, so that bugs me even more, because it'd be really nice to have the
     8  // state data be exactly 100 bytes.  So these functions "compress" the signatures
     9  // into 65 bytes, and restore back into the ~71 byte normal length.
    10  
    11  func SigCompress(sig []byte) (csig [64]byte, err error) {
    12  	if len(sig) < 65 || len(sig) > 72 {
    13  		err = fmt.Errorf("Can't compress; sig length is %d", len(sig))
    14  		return
    15  	}
    16  	if sig[0] != 0x30 {
    17  		err = fmt.Errorf("Can't compress; sig starts with %x instead of 30", sig[0])
    18  		return
    19  	}
    20  
    21  	// on the web it says sigs can be 72 or even 73 bytes, which I guess means that
    22  	// s can also be 33 bytes?  But I've never seen it.  Maybe 73 is from the
    23  	// sighash byte at the end?  Seems like 65 is enough.
    24  
    25  	var r [32]byte
    26  	var s [32]byte
    27  
    28  	// pop off first byte of signature which is always 30
    29  	sig = sig[1:]
    30  
    31  	// check reported length vs actual length
    32  	if int(sig[0]) != len(sig)-1 {
    33  		err = fmt.Errorf("length byte is %x (%d) but rest is %d bytes long",
    34  			sig[0], sig[0], len(sig)-1)
    35  	}
    36  	// pop off another byte (the length byte)
    37  	sig = sig[1:]
    38  
    39  	// 0x02 here just for fun
    40  	if sig[0] != 0x02 {
    41  		err = fmt.Errorf("should have an 0x02 byte, %x instead", sig[0])
    42  		return
    43  	}
    44  	// and pop off that
    45  	sig = sig[1:]
    46  
    47  	// get length of R
    48  	rlen := sig[0]
    49  	// pop that off
    50  	sig = sig[1:]
    51  	// check rlen
    52  	if rlen < 22 || rlen > 33 {
    53  		err = fmt.Errorf("%d byte r is too long", rlen)
    54  		return
    55  	}
    56  	if int(rlen) > len(sig) {
    57  		err = fmt.Errorf("length of r value %d but only %d bytes left ",
    58  			rlen, len(sig))
    59  	}
    60  	if rlen == 33 { //drop 0 byte if rlen is 33
    61  		sig = sig[1:]
    62  		rlen = 32
    63  	}
    64  	// copy r, leaving 0s at the MSB
    65  	copy(r[32-rlen:], sig[:rlen])
    66  	// pop off r
    67  	sig = sig[rlen:]
    68  
    69  	// 0x02 again, just for fun
    70  	if sig[0] != 0x02 {
    71  		err = fmt.Errorf("should have an 0x02 byte, %x instead", sig[0])
    72  		return
    73  	}
    74  	// and pop off that
    75  	sig = sig[1:]
    76  
    77  	// get length of s
    78  	slen := sig[0]
    79  	// pop that off
    80  	sig = sig[1:]
    81  	// check slen
    82  	if slen < 22 || slen > 33 {
    83  		err = fmt.Errorf("%d byte s is too long", slen)
    84  		return
    85  	}
    86  	if int(slen) > len(sig) {
    87  		err = fmt.Errorf("length of s value %d but only %d bytes left ",
    88  			slen, len(sig))
    89  	}
    90  	if slen == 33 { //drop 0 byte if slen is 33
    91  		sig = sig[1:]
    92  		slen = 32
    93  	}
    94  	// copy s, leaving 0s at the MSB
    95  	copy(s[32-slen:], sig[:slen])
    96  	// we're done with sig
    97  	// serialize compressed sig as r, s
    98  	copy(csig[0:32], r[:])
    99  	copy(csig[32:64], s[:])
   100  
   101  	return
   102  }
   103  
   104  /*
   105  3045 0221 00b7cfe9d300b30f9705633c3b031f8312a189dde2be5aad2e28d73aa617d8ad42 0220 4ff09fd52705fee8733129466e9da417c17b99496360a9a202172b92b8bc78ef
   106  3044 0220   77bd60f213f867e44c85810ebd69e0cf365cf2f20d45264d017b9dde366836d8 0220 00cf16a67d3ca7eee2297e7720e3c077a0a48a7dbbc649bea73d436e2f8c2af9
   107  3045 0221 00bb6300be5526b13f901532c29ce9609e944c1124b13c96f86dd096ac50bafbea 0220 12d39d7a72ea859bd8d31e0a7ea96e2307da100d6ff9c86ab2a83cd17a8ef222
   108  3045 0221 00e9dd01c5cf1b0fbb80af1949def0b226a232acace2a744a01fea73d4897bea9c 0220 526976d608f704e570687dc410edc1c885030ca3aa71f646590e1f0f482fc146
   109  3045 0221 00b4053184157f00bdbf1ff67e411197dd0a46cf410c4abc0d8ea8c3155b0afec7 0220 425ddfe133ee43c3edb99834054db6d46b09b613ec3fea59dc35780fbd9ace72
   110  3044 0220   6048246c95429555d265472d936b71e728f468a84412f9423941b4b9cbbab2f0 0220 4eb1bf82879c72adc3390a638a221792adecf74a097de9bd1257b5bc3e17a407
   111  3045 0221 00b88e7a9137efe437cae4f3dd5e0d05bdf9cf519c10c36d2f657d6bbb0906a50f 0220 41c95b40dc5423864022f5d110a810c50c1dd72c4b679da75e0134f4f5903609
   112  3044 0220   20797760653290231de963a89154a3977685357c2868ae0fb0d241522b62a5c2 0220 211c56e794bf8f04624898094cb4f6beaeff3055bede0c0e5be9cc78b17def22
   113  3044 0220   7652fbfc921747befbcb4193a13b469ddecb767316f1470a01717d758666221f 0220 32131428c3801fd6fa7038b451e7adb4db281e7b38414a8cbc4c604c51574df5
   114  
   115  3045 0220   59f28edc62e4b744ff7097717b7d4701614e4af6a30dfa2081ef3e8e27924184 0221 008279ca7eb40a4bd04c923b96110b00d472d648c67df09ad39945130b8f7e4dc8
   116  
   117  3044 0220   3af596f8fbeed4c1e6222aecda133c229708c6982c6c98b69a3820331c64d3e0 0220 4f853d4ecea9c7ff0f30fd8e7b47ceddcc0ab2a4d49271062d4e63cc4181354f
   118  
   119  3044 0220   57a56687d15830950a8b2b8c89507815d9bbd19d85497f5e68277f03eecb9262 0220 07c74cbb0491adc8bcc1d8dc13286eb5ec54925c582a6bce2b5743e2ccf69750
   120  
   121  3045022059f28edc62e4b744ff7097717b7d4701614e4af6a30dfa2081ef3e8e279241840221008279ca7eb40a4bd04c923b96110b00d472d648c67df09ad39945130b8f7e4dc8
   122  304402206048246c95429555d265472d936b71e728f468a84412f9423941b4b9cbbab2f002204eb1bf82879c72adc3390a638a221792adecf74a097de9bd1257b5bc3e17a407
   123  3045022100b88e7a9137efe437cae4f3dd5e0d05bdf9cf519c10c36d2f657d6bbb0906a50f022041c95b40dc5423864022f5d110a810c50c1dd72c4b679da75e0134f4f5903609
   124  
   125  */
   126  
   127  func SigDecompress(csig [64]byte) (sig []byte) {
   128  	// this never fails, which is nicer eh?
   129  
   130  	// check the beginning of r for 0s.  weird padding.
   131  	rlen := 33
   132  	// chop down to 32 if msb is not set
   133  	if csig[0]&0x80 == 0 {
   134  		rlen--
   135  	}
   136  	// keep chopping down as needed
   137  	i := 0
   138  	for rlen > 1 && csig[i] == 0 && csig[i+1]&0x80 == 0 {
   139  		rlen--
   140  		i++
   141  	}
   142  	padr := make([]byte, rlen)
   143  	copy(padr[rlen-(32-i):], csig[i:])
   144  
   145  	// same with s.
   146  	slen := 33
   147  	// chop down to 32 if msb is not set
   148  	if csig[32]&0x80 == 0 {
   149  		slen--
   150  	}
   151  	// keep chopping down as needed
   152  	i = 32
   153  	for slen > 1 && csig[i] == 0 && csig[i+1]&0x80 == 0 {
   154  		slen--
   155  		i++
   156  	}
   157  	pads := make([]byte, slen)
   158  	copy(pads[slen-(64-i):], csig[i:])
   159  
   160  	fulllen := byte(len(padr) + len(pads) + 6)
   161  	sig = make([]byte, fulllen)
   162  	sig[0] = 0x30
   163  	sig[1] = fulllen - 2 // the 0x30, and this byte itself
   164  	sig[2] = 0x02
   165  	sig[3] = byte(len(padr))
   166  	// got this copy / offset trick from koblitz/signature.go
   167  	endr := copy(sig[4:], padr) + 4
   168  	sig[endr] = 0x02
   169  	sig[endr+1] = byte(len(pads))
   170  	copy(sig[endr+2:], pads)
   171  
   172  	return
   173  }