shadow_wire.go raw
1 package crypto
2
3 import (
4 "encoding/binary"
5 "errors"
6 )
7
8 // Shadow compression wire format magic bytes.
9 var shadowMagic = [4]byte{'S', 'D', 'W', '1'}
10
11 // MarshalShadowCompressed encodes a ShadowCompressed into the binary
12 // wire format.
13 //
14 // Layout:
15 //
16 // [4B] Magic "SDW1"
17 // [4B] OrigLen (uint32 LE)
18 // [4B] TokenCount (uint32 LE)
19 // [2B] EpochDecExp (uint16 LE)
20 // [2B] EpochBinExp (uint16 LE)
21 // [4B] PrimaryLen (uint32 LE)
22 // [4B] ShadowLen (uint32 LE)
23 // [4B] ShadowPayloadLen (uint32 LE)
24 // [256B] FreqTable (64 × uint32 LE)
25 // [56B] ContentHash (Hamadryad)
26 // [PrimaryLen B] Huffman bitstream
27 // [ShadowLen B] Shadow permutation indices
28 func MarshalShadowCompressed(sc *ShadowCompressed) ([]byte, error) {
29 if sc == nil {
30 return nil, errors.New("crypto: nil shadow compressed")
31 }
32
33 headerSize := 4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 256 + HamBytes // 340
34 totalSize := headerSize + len(sc.Primary) + len(sc.Shadow)
35 buf := make([]byte, totalSize)
36 pos := 0
37
38 // Magic.
39 copy(buf[pos:], shadowMagic[:])
40 pos += 4
41
42 // OrigLen.
43 binary.LittleEndian.PutUint32(buf[pos:], uint32(sc.OrigLen))
44 pos += 4
45
46 // TokenCount.
47 binary.LittleEndian.PutUint32(buf[pos:], uint32(sc.TokenCount))
48 pos += 4
49
50 // EpochDecExp.
51 binary.LittleEndian.PutUint16(buf[pos:], uint16(sc.EpochDec))
52 pos += 2
53
54 // EpochBinExp.
55 binary.LittleEndian.PutUint16(buf[pos:], uint16(sc.EpochBin))
56 pos += 2
57
58 // PrimaryLen.
59 binary.LittleEndian.PutUint32(buf[pos:], uint32(len(sc.Primary)))
60 pos += 4
61
62 // ShadowLen.
63 binary.LittleEndian.PutUint32(buf[pos:], uint32(len(sc.Shadow)))
64 pos += 4
65
66 // ShadowPayloadLen.
67 binary.LittleEndian.PutUint32(buf[pos:], uint32(sc.ShadowPayloadLen))
68 pos += 4
69
70 // FreqTable: 64 × uint32.
71 for i := range 64 {
72 binary.LittleEndian.PutUint32(buf[pos:], sc.FreqTable[i])
73 pos += 4
74 }
75
76 // ContentHash.
77 copy(buf[pos:], sc.ContentHash[:])
78 pos += HamBytes
79
80 // Primary stream.
81 copy(buf[pos:], sc.Primary)
82 pos += len(sc.Primary)
83
84 // Shadow stream.
85 copy(buf[pos:], sc.Shadow)
86
87 return buf, nil
88 }
89
90 // UnmarshalShadowCompressed decodes a ShadowCompressed from the binary
91 // wire format.
92 func UnmarshalShadowCompressed(data []byte) (*ShadowCompressed, error) {
93 headerSize := 4 + 4 + 4 + 2 + 2 + 4 + 4 + 4 + 256 + HamBytes
94 if len(data) < headerSize {
95 return nil, errors.New("crypto: shadow compressed data too short")
96 }
97 pos := 0
98
99 // Magic.
100 if data[0] != 'S' || data[1] != 'D' || data[2] != 'W' || data[3] != '1' {
101 return nil, errors.New("crypto: invalid shadow compressed magic")
102 }
103 pos += 4
104
105 sc := &ShadowCompressed{}
106
107 // OrigLen.
108 sc.OrigLen = int(binary.LittleEndian.Uint32(data[pos:]))
109 pos += 4
110
111 // TokenCount.
112 sc.TokenCount = int(binary.LittleEndian.Uint32(data[pos:]))
113 pos += 4
114
115 // EpochDecExp.
116 sc.EpochDec = int(binary.LittleEndian.Uint16(data[pos:]))
117 pos += 2
118
119 // EpochBinExp.
120 sc.EpochBin = int(binary.LittleEndian.Uint16(data[pos:]))
121 pos += 2
122
123 // PrimaryLen.
124 primaryLen := int(binary.LittleEndian.Uint32(data[pos:]))
125 pos += 4
126
127 // ShadowLen.
128 shadowLen := int(binary.LittleEndian.Uint32(data[pos:]))
129 pos += 4
130
131 // ShadowPayloadLen.
132 sc.ShadowPayloadLen = int(binary.LittleEndian.Uint32(data[pos:]))
133 pos += 4
134
135 // FreqTable.
136 for i := range 64 {
137 sc.FreqTable[i] = binary.LittleEndian.Uint32(data[pos:])
138 pos += 4
139 }
140
141 // ContentHash.
142 copy(sc.ContentHash[:], data[pos:pos+HamBytes])
143 pos += HamBytes
144
145 // Bounds check.
146 if pos+primaryLen+shadowLen > len(data) {
147 return nil, errors.New("crypto: shadow compressed data truncated")
148 }
149
150 // Primary stream.
151 sc.Primary = make([]byte, primaryLen)
152 copy(sc.Primary, data[pos:pos+primaryLen])
153 pos += primaryLen
154
155 // Shadow stream.
156 sc.Shadow = make([]byte, shadowLen)
157 copy(sc.Shadow, data[pos:pos+shadowLen])
158
159 return sc, nil
160 }
161