github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/signature/signer_indices.go (about) 1 package signature 2 3 import ( 4 "errors" 5 "fmt" 6 7 "github.com/onflow/flow-go/ledger/common/bitutils" 8 "github.com/onflow/flow-go/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.IdentitySkeletonList, 131 sigType []byte, 132 ) (flow.IdentitySkeletonList, flow.IdentitySkeletonList, 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 IdentitySkeletonList 142 stakingSigners := make(flow.IdentitySkeletonList, 0, numberSigners) 143 beaconSigners := make(flow.IdentitySkeletonList, 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 // - `signerIDs` can be in arbitrary order (canonical order _not required_) 160 // 161 // RETURN VALUE: 162 // - `signerIndices` is a bit vector. Let signerIndices[i] denote the ith bit of `signerIndices`. 163 // . ┌ 1 if and only if canonicalIdentifiers[i] is in `signerIDs` 164 // . signerIndices[i] = └ 0 otherwise 165 // Let `n` be the length of `canonicalIdentifiers`. `signerIndices` contains at least `n` bits, though, we 166 // right-pad it with tailing zeros to full bytes. 167 // 168 // Example: 169 // As an example consider the case where we have a committee C of 10 nodes in canonical oder 170 // 171 // C = [A,B,C,D,E,F,G,H,I,J] 172 // 173 // where nodes [B,F] are stakingSigners, and beaconSigners are [C,E,G,I,J]. 174 // 1. First return parameter: QC.signerIndices 175 // - We start with a bit vector v that has |C| number of bits 176 // - If a node contributed either as staking signer or beacon signer, 177 // we set the respective bit to 1: 178 // . [A,B,C,D,E,F,G,H,I,J] 179 // . ↓ ↓ ↓ ↓ ↓ ↓ ↓ 180 // . 0,1,1,0,1,1,1,0,1,1 181 // - Lastly, right-pad the resulting bit vector with 0 to full bytes. We have 10 committee members, 182 // so we pad to 2 bytes: 183 // . 01101110 11000000 184 // 185 // ERROR RETURNS 186 // During normal operations, no error returns are expected. This is because encoding signer sets is generally 187 // part of the node's internal work to generate messages. Hence, the inputs to this method come from other 188 // trusted components within the node. Therefore, any illegal input is treated as a symptom of an internal bug. 189 // canonicalIdentifiers represents all identities who are eligible to sign the given resource. It excludes 190 // identities who are ineligible to sign the given resource. For example, canonicalIdentifiers in the context 191 // of a cluster consensus quorum certificate would include authorized members of the cluster and 192 // exclude ejected members of the cluster, or unejected collection nodes from a different cluster. 193 // the signer indices is prefixed with a checksum of the canonicalIdentifiers, which can be used by the decoder 194 // to verify if the decoder is using the same canonicalIdentifiers as the encoder to decode the signer indices. 195 func EncodeSignersToIndices( 196 canonicalIdentifiers flow.IdentifierList, 197 signerIDs flow.IdentifierList, 198 ) (signerIndices []byte, err error) { 199 signersLookup := signerIDs.Lookup() 200 if len(signersLookup) != len(signerIDs) { 201 return nil, fmt.Errorf("duplicated entries in signerIDs %v", signerIDs) 202 } 203 204 // encode Identifiers to bits 205 signerIndices = bitutils.MakeBitVector(len(canonicalIdentifiers)) 206 for canonicalIdx, member := range canonicalIdentifiers { 207 if _, ok := signersLookup[member]; ok { 208 bitutils.SetBit(signerIndices, canonicalIdx) 209 delete(signersLookup, member) 210 } 211 } 212 if len(signersLookup) > 0 { 213 return nil, fmt.Errorf("unknown signers IDs in the keys of %v", signersLookup) 214 } 215 216 prefixed := PrefixCheckSum(canonicalIdentifiers, signerIndices) 217 218 return prefixed, nil 219 } 220 221 // DecodeSignerIndicesToIdentifiers decodes the given compacted bit vector into signerIDs 222 // Prerequisite: 223 // - The input `canonicalIdentifiers` must exhaustively list the set of authorized signers in their canonical order. 224 // 225 // Expected Error returns during normal operations: 226 // * signature.InvalidSignerIndicesError if the given index vector `prefixed` does not encode a valid set of signers 227 func DecodeSignerIndicesToIdentifiers( 228 canonicalIdentifiers flow.IdentifierList, 229 prefixed []byte, 230 ) (flow.IdentifierList, error) { 231 indices, err := decodeSignerIndices(canonicalIdentifiers, prefixed) 232 if err != nil { 233 return nil, err 234 } 235 236 signerIDs := make(flow.IdentifierList, 0, len(indices)) 237 for _, index := range indices { 238 signerIDs = append(signerIDs, canonicalIdentifiers[index]) 239 } 240 return signerIDs, nil 241 } 242 243 func decodeSignerIndices( 244 canonicalIdentifiers flow.IdentifierList, 245 prefixed []byte, 246 ) ([]int, error) { 247 // the prefixed contains the checksum of the canonicalIdentifiers that the signerIndices 248 // creator saw. 249 // extract the checksum and compare with the canonicalIdentifiers to see if both 250 // the signerIndices creator and validator see the same list. 251 signerIndices, err := CompareAndExtract(canonicalIdentifiers, prefixed) 252 if err != nil { 253 if errors.Is(err, ErrInvalidChecksum) { 254 return nil, NewInvalidSignerIndicesErrorf("signer indices' checkum is invalid: %w", err) 255 } 256 return nil, fmt.Errorf("unexpected exception while checking signer indices: %w", err) 257 } 258 259 numberCanonicalNodes := len(canonicalIdentifiers) 260 err = validPadding(signerIndices, numberCanonicalNodes) 261 if err != nil { 262 if errors.Is(err, ErrIncompatibleBitVectorLength) || errors.Is(err, ErrIllegallyPaddedBitVector) { 263 return nil, NewInvalidSignerIndicesErrorf("invalid padding of signerIndices: %w", err) 264 } 265 return nil, fmt.Errorf("unexpected exception while checking padding of signer indices: %w", err) 266 } 267 268 // decode bits to Identifiers 269 indices := make([]int, 0, numberCanonicalNodes) 270 for i := 0; i < numberCanonicalNodes; i++ { 271 if bitutils.ReadBit(signerIndices, i) == 1 { 272 indices = append(indices, i) 273 } 274 } 275 return indices, nil 276 } 277 278 // DecodeSignerIndicesToIdentities decodes the given compacted bit vector into node Identities. 279 // Prerequisite: 280 // - The input `canonicalIdentifiers` must exhaustively list the set of authorized signers in their canonical order. 281 // 282 // The returned list of decoded identities is in canonical order. 283 // 284 // Expected Error returns during normal operations: 285 // * signature.InvalidSignerIndicesError if the given index vector `prefixed` does not encode a valid set of signers 286 func DecodeSignerIndicesToIdentities( 287 canonicalIdentities flow.IdentitySkeletonList, 288 prefixed []byte, 289 ) (flow.IdentitySkeletonList, error) { 290 indices, err := decodeSignerIndices(canonicalIdentities.NodeIDs(), prefixed) 291 if err != nil { 292 return nil, err 293 } 294 295 signers := make(flow.IdentitySkeletonList, 0, len(indices)) 296 for _, index := range indices { 297 signers = append(signers, canonicalIdentities[index]) 298 } 299 return signers, nil 300 } 301 302 // validPadding verifies that `bitVector` satisfies the following criteria 303 // 1. The `bitVector`'s length [in bytes], must be the _minimal_ possible length such that it can hold 304 // `numUsedBits` number of bits. Otherwise, we return an `ErrIncompatibleBitVectorLength`. 305 // 2. If `numUsedBits` is _not_ an integer-multiple of 8, `bitVector` is padded with tailing bits. Per 306 // convention, these bits must be zero. Otherwise, we return an `ErrIllegallyPaddedBitVector`. 307 // 308 // Expected Error returns during normal operations: 309 // - ErrIncompatibleBitVectorLength if the vector has the wrong length 310 // - ErrIllegallyPaddedBitVector if the vector is padded with bits other than 0 311 func validPadding(bitVector []byte, numUsedBits int) error { 312 // Verify condition 1: 313 l := len(bitVector) 314 if l != bitutils.MinimalByteSliceLength(numUsedBits) { 315 return fmt.Errorf("the bit vector contains a payload of %d used bits, so it should have %d bytes but has %d bytes: %w", 316 numUsedBits, bitutils.MinimalByteSliceLength(numUsedBits), l, ErrIncompatibleBitVectorLength) 317 } 318 // Condition 1 implies that the number of padded bits must be strictly smaller than 8. Otherwise, the vector 319 // could have fewer bytes and still have enough room to store `numUsedBits`. 320 321 // Verify condition 2, i.e. that all padded bits are all 0: 322 // * As `bitVector` passed check 1, all padded bits are located in `bitVector`s _last byte_. 323 // * Let `lastByte` be the last byte of `bitVector`. The leading bits, specifically `numUsedBits & 7`, 324 // belong to the used payload, which could have non-zero values. We remove these using left-bit-shifts. 325 // The result contains exactly all padded bits (plus some auxiliary 0-bits included by the bit-shift 326 // operator). Hence, condition 2 is satisfied if and only if the result is identical to zero. 327 // Note that this implementation is much more efficient than individually checking the padded bits, as we check all 328 // padded bits at once; furthermore, we only use multiplication, subtraction, shift, which are fast. 329 if numUsedBits&7 == 0 { // if numUsedBits is multiple of 8, then there are no padding bits to check 330 return nil 331 } 332 // the above check has ensured that lastByte does exist (l==0 is excluded) 333 lastByte := bitVector[l-1] 334 if (lastByte << (numUsedBits & 7)) != 0 { // shift by numUsedBits % 8 335 return fmt.Errorf("some padded bits are not zero with %d used bits (bitVector: %x): %w", numUsedBits, bitVector, ErrIllegallyPaddedBitVector) 336 } 337 338 return nil 339 }