github.com/koko1123/flow-go-1@v0.29.6/module/signature/signer_indices.go (about) 1 package signature 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/koko1123/flow-go-1/ledger/common/bitutils" 8 "github.com/koko1123/flow-go-1/model/flow" 9 ) 10 11 // EncodeSignerToIndicesAndSigType encodes the given stakingSigners and beaconSigners into bit vectors for 12 // signer indices and sig types. 13 // PREREQUISITES: 14 // - The input `canonicalIdentifiers` must exhaustively list the set of authorized signers in their canonical order. 15 // - The inputs `stakingSigners` and `beaconSigners` are treated as sets, i.e. they 16 // should not contain any duplicates. 17 // - A node can be listed in either `stakingSigners` or `beaconSigners`. A node appearing in both lists 18 // constitutes an illegal input. 19 // - `stakingSigners` must be a subset of `canonicalIdentifiers` 20 // - `beaconSigners` must be a subset of `canonicalIdentifiers` 21 // 22 // RETURN VALUES: 23 // 24 // - `signerIndices` is a bit vector. Let signerIndices[i] denote the ith bit of `signerIndices`. 25 // 26 // . ┌ 1 if and only if canonicalIdentifiers[i] is in `stakingSigners` or `beaconSigners` 27 // . signerIndices[i] = └ 0 otherwise 28 // 29 // Let `n` be the length of `canonicalIdentifiers`. `signerIndices` contains at least `n` bits, though, we 30 // right-pad it with tailing zeros to full bytes. 31 // 32 // - `sigTypes` is a bit vector. Let sigTypes[i] denote the ith bit of `sigTypes` 33 // . ┌ 1 if and only if the ith signer is in `beaconSigners` 34 // . sigTypes[i] = └ 0 if and only if the ith signer is in `stakingSigners` 35 // (Per prerequisite, we require that no signer is listed in both `beaconSigners` and `stakingSigners`) 36 // 37 // Example: 38 // As an example consider the case where we have a committee C of 10 nodes in canonical oder 39 // 40 // C = [A,B,C,D,E,F,G,H,I,J] 41 // 42 // where nodes [B,F] are stakingSigners and beaconSigners are [C,E,G,I,J]. 43 // 1. First return parameter: `signerIndices` 44 // - We start with a bit vector v that has |C| number of bits 45 // - If a node contributed either as staking signer or beacon signer, 46 // we set the respective bit to 1: 47 // . [A,B,C,D,E,F,G,H,I,J] 48 // . ↓ ↓ ↓ ↓ ↓ ↓ ↓ 49 // . 0,1,1,0,1,1,1,0,1,1 50 // - Lastly, right-pad the resulting bit vector with 0 to full bytes. We have 10 committee members, 51 // so we pad to 2 bytes: 52 // . 01101110 11000000 53 // 2. second return parameter: `sigTypes` 54 // - Here, we restrict our focus on the signers, which we encoded in the previous step. 55 // In our example, nodes [B,C,E,F,G,I,J] signed in canonical order. This is exactly the same order, 56 // as we have represented the signer in the last step. 57 // - For these 5 nodes in their canonical order, we encode each node's signature type as 58 // . bit-value 1: node was in beaconSigners 59 // . bit-value 0: node was in stakingSigners 60 // This results in the bit vector 61 // . [B,C,E,F,G,I,J] 62 // . ↓ ↓ ↓ ↓ ↓ ↓ ↓ 63 // . 0,1,0,1,1,1,1 64 // - Again, we right-pad with zeros to full bytes, As we only had 7 signers, the sigType slice is 1byte long 65 // . 01011110 66 // 67 // the signer indices is prefixed with a checksum of the canonicalIdentifiers, which can be used by the decoder 68 // to verify if the decoder is using the same canonicalIdentifiers as the encoder to decode the signer indices. 69 // 70 // ERROR RETURNS 71 // During normal operations, no error returns are expected. This is because encoding signer sets is generally 72 // part of the node's internal work to generate messages. Hence, the inputs to this method come from other 73 // trusted components within the node. Therefore, any illegal input is treated as a symptom of an internal bug. 74 func EncodeSignerToIndicesAndSigType( 75 canonicalIdentifiers flow.IdentifierList, 76 stakingSigners flow.IdentifierList, 77 beaconSigners flow.IdentifierList, 78 ) (signerIndices []byte, sigTypes []byte, err error) { 79 stakingSignersLookup := stakingSigners.Lookup() 80 if len(stakingSignersLookup) != len(stakingSigners) { 81 return nil, nil, fmt.Errorf("duplicated entries in staking signers %v", stakingSignersLookup) 82 } 83 beaconSignersLookup := beaconSigners.Lookup() 84 if len(beaconSignersLookup) != len(beaconSigners) { 85 return nil, nil, fmt.Errorf("duplicated entries in beacon signers %v", stakingSignersLookup) 86 } 87 88 // encode Identifiers to `signerIndices`; and for each signer, encode the signature type in `sigTypes` 89 signerIndices = bitutils.MakeBitVector(len(canonicalIdentifiers)) 90 sigTypes = bitutils.MakeBitVector(len(stakingSigners) + len(beaconSigners)) 91 signerCounter := 0 92 for canonicalIdx, member := range canonicalIdentifiers { 93 if _, ok := stakingSignersLookup[member]; ok { 94 bitutils.SetBit(signerIndices, canonicalIdx) 95 // The default value for sigTypes is bit zero, which corresponds to a staking sig. 96 // Hence, we don't have to change anything here. 97 delete(stakingSignersLookup, member) 98 signerCounter++ 99 continue 100 } 101 if _, ok := beaconSignersLookup[member]; ok { 102 bitutils.SetBit(signerIndices, canonicalIdx) 103 bitutils.SetBit(sigTypes, signerCounter) 104 delete(beaconSignersLookup, member) 105 signerCounter++ 106 continue 107 } 108 } 109 110 if len(stakingSignersLookup) > 0 { 111 return nil, nil, fmt.Errorf("unknown staking signers %v", stakingSignersLookup) 112 } 113 if len(beaconSignersLookup) > 0 { 114 return nil, nil, fmt.Errorf("unknown or duplicated beacon signers %v", beaconSignersLookup) 115 } 116 117 prefixed := PrefixCheckSum(canonicalIdentifiers, signerIndices) 118 119 return prefixed, sigTypes, nil 120 } 121 122 // DecodeSigTypeToStakingAndBeaconSigners decodes the bit-vector `sigType` to the set of 123 // staking signer identities (`stakingSigners`) and the set of beacon signer identities (`beaconSigners`). 124 // Prerequisite: 125 // - The input `signers` must be the set of signers in their canonical order. 126 // 127 // Expected Error returns during normal operations: 128 // - signature.IsInvalidSigTypesError if the given `sigType` does not encode a valid sequence of signature types 129 func DecodeSigTypeToStakingAndBeaconSigners( 130 signers flow.IdentityList, 131 sigType []byte, 132 ) (flow.IdentityList, flow.IdentityList, error) { 133 numberSigners := len(signers) 134 if err := validPadding(sigType, numberSigners); err != nil { 135 if errors.Is(err, ErrIncompatibleBitVectorLength) || errors.Is(err, ErrIllegallyPaddedBitVector) { 136 return nil, nil, NewInvalidSigTypesErrorf("invalid padding of sigTypes: %w", err) 137 } 138 return nil, nil, fmt.Errorf("unexpected exception while checking padding of sigTypes: %w", err) 139 } 140 141 // decode bits to Identities 142 stakingSigners := make(flow.IdentityList, 0, numberSigners) 143 beaconSigners := make(flow.IdentityList, 0, numberSigners) 144 for i, signer := range signers { 145 if bitutils.ReadBit(sigType, i) == 0 { 146 stakingSigners = append(stakingSigners, signer) 147 } else { 148 beaconSigners = append(beaconSigners, signer) 149 } 150 } 151 return stakingSigners, beaconSigners, nil 152 } 153 154 // EncodeSignersToIndices encodes the given signerIDs into compacted bit vector. 155 // PREREQUISITES: 156 // - The input `canonicalIdentifiers` must exhaustively list the set of authorized signers in their canonical order. 157 // - The input `signerIDs` represents a set, i.e. it should not contain any duplicates. 158 // - `signerIDs` must be a subset of `canonicalIdentifiers` 159 // 160 // RETURN VALUE: 161 // - `signerIndices` is a bit vector. Let signerIndices[i] denote the ith bit of `signerIndices`. 162 // . ┌ 1 if and only if canonicalIdentifiers[i] is in `signerIDs` 163 // . signerIndices[i] = └ 0 otherwise 164 // Let `n` be the length of `canonicalIdentifiers`. `signerIndices` contains at least `n` bits, though, we 165 // right-pad it with tailing zeros to full bytes. 166 // 167 // Example: 168 // As an example consider the case where we have a committee C of 10 nodes in canonical oder 169 // 170 // C = [A,B,C,D,E,F,G,H,I,J] 171 // 172 // where nodes [B,F] are stakingSigners, and beaconSigners are [C,E,G,I,J]. 173 // 1. First return parameter: QC.signerIndices 174 // - We start with a bit vector v that has |C| number of bits 175 // - If a node contributed either as staking signer or beacon signer, 176 // we set the respective bit to 1: 177 // . [A,B,C,D,E,F,G,H,I,J] 178 // . ↓ ↓ ↓ ↓ ↓ ↓ ↓ 179 // . 0,1,1,0,1,1,1,0,1,1 180 // - Lastly, right-pad the resulting bit vector with 0 to full bytes. We have 10 committee members, 181 // so we pad to 2 bytes: 182 // . 01101110 11000000 183 // 184 // ERROR RETURNS 185 // During normal operations, no error returns are expected. This is because encoding signer sets is generally 186 // part of the node's internal work to generate messages. Hence, the inputs to this method come from other 187 // trusted components within the node. Therefore, any illegal input is treated as a symptom of an internal bug. 188 // canonicalIdentifiers represents all identities who are eligible to sign the given resource. It excludes 189 // identities who are ineligible to sign the given resource. For example, canonicalIdentifiers in the context 190 // of a cluster consensus quorum certificate would include authorized members of the cluster and 191 // exclude ejected members of the cluster, or unejected collection nodes from a different cluster. 192 // the signer indices is prefixed with a checksum of the canonicalIdentifiers, which can be used by the decoder 193 // to verify if the decoder is using the same canonicalIdentifiers as the encoder to decode the signer indices. 194 func EncodeSignersToIndices( 195 canonicalIdentifiers flow.IdentifierList, 196 signerIDs flow.IdentifierList, 197 ) (signerIndices []byte, err error) { 198 signersLookup := signerIDs.Lookup() 199 if len(signersLookup) != len(signerIDs) { 200 return nil, fmt.Errorf("duplicated entries in signerIDs %v", signerIDs) 201 } 202 203 // encode Identifiers to bits 204 signerIndices = bitutils.MakeBitVector(len(canonicalIdentifiers)) 205 for canonicalIdx, member := range canonicalIdentifiers { 206 if _, ok := signersLookup[member]; ok { 207 bitutils.SetBit(signerIndices, canonicalIdx) 208 delete(signersLookup, member) 209 } 210 } 211 if len(signersLookup) > 0 { 212 return nil, fmt.Errorf("unknown signers IDs in the keys of %v", signersLookup) 213 } 214 215 prefixed := PrefixCheckSum(canonicalIdentifiers, signerIndices) 216 217 return prefixed, nil 218 } 219 220 // DecodeSignerIndicesToIdentifiers decodes the given compacted bit vector into signerIDs 221 // Prerequisite: 222 // - The input `canonicalIdentifiers` must exhaustively list the set of authorized signers in their canonical order. 223 // 224 // Expected Error returns during normal operations: 225 // * signature.InvalidSignerIndicesError if the given index vector `prefixed` does not encode a valid set of signers 226 func DecodeSignerIndicesToIdentifiers( 227 canonicalIdentifiers flow.IdentifierList, 228 prefixed []byte, 229 ) (flow.IdentifierList, error) { 230 indices, err := decodeSignerIndices(canonicalIdentifiers, prefixed) 231 if err != nil { 232 return nil, err 233 } 234 235 signerIDs := make(flow.IdentifierList, 0, len(indices)) 236 for _, index := range indices { 237 signerIDs = append(signerIDs, canonicalIdentifiers[index]) 238 } 239 return signerIDs, nil 240 } 241 242 func decodeSignerIndices( 243 canonicalIdentifiers flow.IdentifierList, 244 prefixed []byte, 245 ) ([]int, error) { 246 // the prefixed contains the checksum of the canonicalIdentifiers that the signerIndices 247 // creator saw. 248 // extract the checksum and compare with the canonicalIdentifiers to see if both 249 // the signerIndices creator and validator see the same list. 250 signerIndices, err := CompareAndExtract(canonicalIdentifiers, prefixed) 251 if err != nil { 252 if errors.Is(err, ErrInvalidChecksum) { 253 return nil, NewInvalidSignerIndicesErrorf("signer indices' checkum is invalid: %w", err) 254 } 255 return nil, fmt.Errorf("unexpected exception while checking signer indices: %w", err) 256 } 257 258 numberCanonicalNodes := len(canonicalIdentifiers) 259 err = validPadding(signerIndices, numberCanonicalNodes) 260 if err != nil { 261 if errors.Is(err, ErrIncompatibleBitVectorLength) || errors.Is(err, ErrIllegallyPaddedBitVector) { 262 return nil, NewInvalidSignerIndicesErrorf("invalid padding of signerIndices: %w", err) 263 } 264 return nil, fmt.Errorf("unexpected exception while checking padding of signer indices: %w", err) 265 } 266 267 // decode bits to Identifiers 268 indices := make([]int, 0, numberCanonicalNodes) 269 for i := 0; i < numberCanonicalNodes; i++ { 270 if bitutils.ReadBit(signerIndices, i) == 1 { 271 indices = append(indices, i) 272 } 273 } 274 return indices, nil 275 } 276 277 // DecodeSignerIndicesToIdentities decodes the given compacted bit vector into node Identities. 278 // Prerequisite: 279 // - The input `canonicalIdentifiers` must exhaustively list the set of authorized signers in their canonical order. 280 // 281 // Expected Error returns during normal operations: 282 // * signature.InvalidSignerIndicesError if the given index vector `prefixed` does not encode a valid set of signers 283 func DecodeSignerIndicesToIdentities( 284 canonicalIdentities flow.IdentityList, 285 prefixed []byte, 286 ) (flow.IdentityList, error) { 287 indices, err := decodeSignerIndices(canonicalIdentities.NodeIDs(), prefixed) 288 if err != nil { 289 return nil, err 290 } 291 292 signers := make(flow.IdentityList, 0, len(indices)) 293 for _, index := range indices { 294 signers = append(signers, canonicalIdentities[index]) 295 } 296 return signers, nil 297 } 298 299 // validPadding verifies that `bitVector` satisfies the following criteria 300 // 1. The `bitVector`'s length [in bytes], must be the _minimal_ possible length such that it can hold 301 // `numUsedBits` number of bits. Otherwise, we return an `ErrIncompatibleBitVectorLength`. 302 // 2. If `numUsedBits` is _not_ an integer-multiple of 8, `bitVector` is padded with tailing bits. Per 303 // convention, these bits must be zero. Otherwise, we return an `ErrIllegallyPaddedBitVector`. 304 // 305 // Expected Error returns during normal operations: 306 // - ErrIncompatibleBitVectorLength if the vector has the wrong length 307 // - ErrIllegallyPaddedBitVector if the vector is padded with bits other than 0 308 func validPadding(bitVector []byte, numUsedBits int) error { 309 // Verify condition 1: 310 l := len(bitVector) 311 if l != bitutils.MinimalByteSliceLength(numUsedBits) { 312 return fmt.Errorf("the bit vector contains a payload of %d used bits, so it should have %d bytes but has %d bytes: %w", 313 numUsedBits, bitutils.MinimalByteSliceLength(numUsedBits), l, ErrIncompatibleBitVectorLength) 314 } 315 // Condition 1 implies that the number of padded bits must be strictly smaller than 8. Otherwise, the vector 316 // could have fewer bytes and still have enough room to store `numUsedBits`. 317 318 // Verify condition 2, i.e. that all padded bits are all 0: 319 // * As `bitVector` passed check 1, all padded bits are located in `bitVector`s _last byte_. 320 // * Let `lastByte` be the last byte of `bitVector`. The leading bits, specifically `numUsedBits & 7`, 321 // belong to the used payload, which could have non-zero values. We remove these using left-bit-shifts. 322 // The result contains exactly all padded bits (plus some auxiliary 0-bits included by the bit-shift 323 // operator). Hence, condition 2 is satisfied if and only if the result is identical to zero. 324 // Note that this implementation is much more efficient than individually checking the padded bits, as we check all 325 // padded bits at once; furthermore, we only use multiplication, subtraction, shift, which are fast. 326 if numUsedBits&7 == 0 { // if numUsedBits is multiple of 8, then there are no padding bits to check 327 return nil 328 } 329 // the above check has ensured that lastByte does exist (l==0 is excluded) 330 lastByte := bitVector[l-1] 331 if (lastByte << (numUsedBits & 7)) != 0 { // shift by numUsedBits % 8 332 return fmt.Errorf("some padded bits are not zero with %d used bits (bitVector: %x): %w", numUsedBits, bitVector, ErrIllegallyPaddedBitVector) 333 } 334 335 return nil 336 }