mirror of
				https://github.com/containers/podman.git
				synced 2025-10-31 18:08:51 +08:00 
			
		
		
		
	 069edc3adf
			
		
	
	069edc3adf
	
	
	
		
			
			(podman push) and (podman manifest push) now support --sign-by-sigstore=param-file, using the containers-sigstore-signing-params.yaml(5) file format. That notably adds support for Fulcio and Rekor signing. Signed-off-by: Miloslav Trmač <mitr@redhat.com>
		
			
				
	
	
		
			344 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package ksuid
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/binary"
 | |
| )
 | |
| 
 | |
| // CompressedSet is an immutable data type which stores a set of KSUIDs.
 | |
| type CompressedSet []byte
 | |
| 
 | |
| // Iter returns an iterator that produces all KSUIDs in the set.
 | |
| func (set CompressedSet) Iter() CompressedSetIter {
 | |
| 	return CompressedSetIter{
 | |
| 		content: []byte(set),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // String satisfies the fmt.Stringer interface, returns a human-readable string
 | |
| // representation of the set.
 | |
| func (set CompressedSet) String() string {
 | |
| 	b := bytes.Buffer{}
 | |
| 	b.WriteByte('[')
 | |
| 	set.writeTo(&b)
 | |
| 	b.WriteByte(']')
 | |
| 	return b.String()
 | |
| }
 | |
| 
 | |
| // String satisfies the fmt.GoStringer interface, returns a Go representation of
 | |
| // the set.
 | |
| func (set CompressedSet) GoString() string {
 | |
| 	b := bytes.Buffer{}
 | |
| 	b.WriteString("ksuid.CompressedSet{")
 | |
| 	set.writeTo(&b)
 | |
| 	b.WriteByte('}')
 | |
| 	return b.String()
 | |
| }
 | |
| 
 | |
| func (set CompressedSet) writeTo(b *bytes.Buffer) {
 | |
| 	a := [27]byte{}
 | |
| 
 | |
| 	for i, it := 0, set.Iter(); it.Next(); i++ {
 | |
| 		if i != 0 {
 | |
| 			b.WriteString(", ")
 | |
| 		}
 | |
| 		b.WriteByte('"')
 | |
| 		it.KSUID.Append(a[:0])
 | |
| 		b.Write(a[:])
 | |
| 		b.WriteByte('"')
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // Compress creates and returns a compressed set of KSUIDs from the list given
 | |
| // as arguments.
 | |
| func Compress(ids ...KSUID) CompressedSet {
 | |
| 	c := 1 + byteLength + (len(ids) / 5)
 | |
| 	b := make([]byte, 0, c)
 | |
| 	return AppendCompressed(b, ids...)
 | |
| }
 | |
| 
 | |
| // AppendCompressed uses the given byte slice as pre-allocated storage space to
 | |
| // build a KSUID set.
 | |
| //
 | |
| // Note that the set uses a compression technique to store the KSUIDs, so the
 | |
| // resuling length is not 20 x len(ids). The rule of thumb here is for the given
 | |
| // byte slice to reserve the amount of memory that the application would be OK
 | |
| // to waste.
 | |
| func AppendCompressed(set []byte, ids ...KSUID) CompressedSet {
 | |
| 	if len(ids) != 0 {
 | |
| 		if !IsSorted(ids) {
 | |
| 			Sort(ids)
 | |
| 		}
 | |
| 		one := makeUint128(0, 1)
 | |
| 
 | |
| 		// The first KSUID is always written to the set, this is the starting
 | |
| 		// point for all deltas.
 | |
| 		set = append(set, byte(rawKSUID))
 | |
| 		set = append(set, ids[0][:]...)
 | |
| 
 | |
| 		timestamp := ids[0].Timestamp()
 | |
| 		lastKSUID := ids[0]
 | |
| 		lastValue := uint128Payload(ids[0])
 | |
| 
 | |
| 		for i := 1; i != len(ids); i++ {
 | |
| 			id := ids[i]
 | |
| 
 | |
| 			if id == lastKSUID {
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			t := id.Timestamp()
 | |
| 			v := uint128Payload(id)
 | |
| 
 | |
| 			if t != timestamp {
 | |
| 				d := t - timestamp
 | |
| 				n := varintLength32(d)
 | |
| 
 | |
| 				set = append(set, timeDelta|byte(n))
 | |
| 				set = appendVarint32(set, d, n)
 | |
| 				set = append(set, id[timestampLengthInBytes:]...)
 | |
| 
 | |
| 				timestamp = t
 | |
| 			} else {
 | |
| 				d := sub128(v, lastValue)
 | |
| 
 | |
| 				if d != one {
 | |
| 					n := varintLength128(d)
 | |
| 
 | |
| 					set = append(set, payloadDelta|byte(n))
 | |
| 					set = appendVarint128(set, d, n)
 | |
| 				} else {
 | |
| 					l, c := rangeLength(ids[i+1:], t, id, v)
 | |
| 					m := uint64(l + 1)
 | |
| 					n := varintLength64(m)
 | |
| 
 | |
| 					set = append(set, payloadRange|byte(n))
 | |
| 					set = appendVarint64(set, m, n)
 | |
| 
 | |
| 					i += c
 | |
| 					id = ids[i]
 | |
| 					v = uint128Payload(id)
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			lastKSUID = id
 | |
| 			lastValue = v
 | |
| 		}
 | |
| 	}
 | |
| 	return CompressedSet(set)
 | |
| }
 | |
| 
 | |
| func rangeLength(ids []KSUID, timestamp uint32, lastKSUID KSUID, lastValue uint128) (length int, count int) {
 | |
| 	one := makeUint128(0, 1)
 | |
| 
 | |
| 	for i := range ids {
 | |
| 		id := ids[i]
 | |
| 
 | |
| 		if id == lastKSUID {
 | |
| 			continue
 | |
| 		}
 | |
| 
 | |
| 		if id.Timestamp() != timestamp {
 | |
| 			count = i
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		v := uint128Payload(id)
 | |
| 
 | |
| 		if sub128(v, lastValue) != one {
 | |
| 			count = i
 | |
| 			return
 | |
| 		}
 | |
| 
 | |
| 		lastKSUID = id
 | |
| 		lastValue = v
 | |
| 		length++
 | |
| 	}
 | |
| 
 | |
| 	count = len(ids)
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func appendVarint128(b []byte, v uint128, n int) []byte {
 | |
| 	c := v.bytes()
 | |
| 	return append(b, c[len(c)-n:]...)
 | |
| }
 | |
| 
 | |
| func appendVarint64(b []byte, v uint64, n int) []byte {
 | |
| 	c := [8]byte{}
 | |
| 	binary.BigEndian.PutUint64(c[:], v)
 | |
| 	return append(b, c[len(c)-n:]...)
 | |
| }
 | |
| 
 | |
| func appendVarint32(b []byte, v uint32, n int) []byte {
 | |
| 	c := [4]byte{}
 | |
| 	binary.BigEndian.PutUint32(c[:], v)
 | |
| 	return append(b, c[len(c)-n:]...)
 | |
| }
 | |
| 
 | |
| func varint128(b []byte) uint128 {
 | |
| 	a := [16]byte{}
 | |
| 	copy(a[16-len(b):], b)
 | |
| 	return makeUint128FromPayload(a[:])
 | |
| }
 | |
| 
 | |
| func varint64(b []byte) uint64 {
 | |
| 	a := [8]byte{}
 | |
| 	copy(a[8-len(b):], b)
 | |
| 	return binary.BigEndian.Uint64(a[:])
 | |
| }
 | |
| 
 | |
| func varint32(b []byte) uint32 {
 | |
| 	a := [4]byte{}
 | |
| 	copy(a[4-len(b):], b)
 | |
| 	return binary.BigEndian.Uint32(a[:])
 | |
| }
 | |
| 
 | |
| func varintLength128(v uint128) int {
 | |
| 	if v[1] != 0 {
 | |
| 		return 8 + varintLength64(v[1])
 | |
| 	}
 | |
| 	return varintLength64(v[0])
 | |
| }
 | |
| 
 | |
| func varintLength64(v uint64) int {
 | |
| 	switch {
 | |
| 	case (v & 0xFFFFFFFFFFFFFF00) == 0:
 | |
| 		return 1
 | |
| 	case (v & 0xFFFFFFFFFFFF0000) == 0:
 | |
| 		return 2
 | |
| 	case (v & 0xFFFFFFFFFF000000) == 0:
 | |
| 		return 3
 | |
| 	case (v & 0xFFFFFFFF00000000) == 0:
 | |
| 		return 4
 | |
| 	case (v & 0xFFFFFF0000000000) == 0:
 | |
| 		return 5
 | |
| 	case (v & 0xFFFF000000000000) == 0:
 | |
| 		return 6
 | |
| 	case (v & 0xFF00000000000000) == 0:
 | |
| 		return 7
 | |
| 	default:
 | |
| 		return 8
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func varintLength32(v uint32) int {
 | |
| 	switch {
 | |
| 	case (v & 0xFFFFFF00) == 0:
 | |
| 		return 1
 | |
| 	case (v & 0xFFFF0000) == 0:
 | |
| 		return 2
 | |
| 	case (v & 0xFF000000) == 0:
 | |
| 		return 3
 | |
| 	default:
 | |
| 		return 4
 | |
| 	}
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	rawKSUID     = 0
 | |
| 	timeDelta    = (1 << 6)
 | |
| 	payloadDelta = (1 << 7)
 | |
| 	payloadRange = (1 << 6) | (1 << 7)
 | |
| )
 | |
| 
 | |
| // CompressedSetIter is an iterator type returned by Set.Iter to produce the
 | |
| // list of KSUIDs stored in a set.
 | |
| //
 | |
| // Here's is how the iterator type is commonly used:
 | |
| //
 | |
| //	for it := set.Iter(); it.Next(); {
 | |
| //		id := it.KSUID
 | |
| //		// ...
 | |
| //	}
 | |
| //
 | |
| // CompressedSetIter values are not safe to use concurrently from multiple
 | |
| // goroutines.
 | |
| type CompressedSetIter struct {
 | |
| 	// KSUID is modified by calls to the Next method to hold the KSUID loaded
 | |
| 	// by the iterator.
 | |
| 	KSUID KSUID
 | |
| 
 | |
| 	content []byte
 | |
| 	offset  int
 | |
| 
 | |
| 	seqlength uint64
 | |
| 	timestamp uint32
 | |
| 	lastValue uint128
 | |
| }
 | |
| 
 | |
| // Next moves the iterator forward, returning true if there a KSUID was found,
 | |
| // or false if the iterator as reached the end of the set it was created from.
 | |
| func (it *CompressedSetIter) Next() bool {
 | |
| 	if it.seqlength != 0 {
 | |
| 		value := incr128(it.lastValue)
 | |
| 		it.KSUID = value.ksuid(it.timestamp)
 | |
| 		it.seqlength--
 | |
| 		it.lastValue = value
 | |
| 		return true
 | |
| 	}
 | |
| 
 | |
| 	if it.offset == len(it.content) {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	b := it.content[it.offset]
 | |
| 	it.offset++
 | |
| 
 | |
| 	const mask = rawKSUID | timeDelta | payloadDelta | payloadRange
 | |
| 	tag := int(b) & mask
 | |
| 	cnt := int(b) & ^mask
 | |
| 
 | |
| 	switch tag {
 | |
| 	case rawKSUID:
 | |
| 		off0 := it.offset
 | |
| 		off1 := off0 + byteLength
 | |
| 
 | |
| 		copy(it.KSUID[:], it.content[off0:off1])
 | |
| 
 | |
| 		it.offset = off1
 | |
| 		it.timestamp = it.KSUID.Timestamp()
 | |
| 		it.lastValue = uint128Payload(it.KSUID)
 | |
| 
 | |
| 	case timeDelta:
 | |
| 		off0 := it.offset
 | |
| 		off1 := off0 + cnt
 | |
| 		off2 := off1 + payloadLengthInBytes
 | |
| 
 | |
| 		it.timestamp += varint32(it.content[off0:off1])
 | |
| 
 | |
| 		binary.BigEndian.PutUint32(it.KSUID[:timestampLengthInBytes], it.timestamp)
 | |
| 		copy(it.KSUID[timestampLengthInBytes:], it.content[off1:off2])
 | |
| 
 | |
| 		it.offset = off2
 | |
| 		it.lastValue = uint128Payload(it.KSUID)
 | |
| 
 | |
| 	case payloadDelta:
 | |
| 		off0 := it.offset
 | |
| 		off1 := off0 + cnt
 | |
| 
 | |
| 		delta := varint128(it.content[off0:off1])
 | |
| 		value := add128(it.lastValue, delta)
 | |
| 
 | |
| 		it.KSUID = value.ksuid(it.timestamp)
 | |
| 		it.offset = off1
 | |
| 		it.lastValue = value
 | |
| 
 | |
| 	case payloadRange:
 | |
| 		off0 := it.offset
 | |
| 		off1 := off0 + cnt
 | |
| 
 | |
| 		value := incr128(it.lastValue)
 | |
| 		it.KSUID = value.ksuid(it.timestamp)
 | |
| 		it.seqlength = varint64(it.content[off0:off1])
 | |
| 		it.offset = off1
 | |
| 		it.seqlength--
 | |
| 		it.lastValue = value
 | |
| 
 | |
| 	default:
 | |
| 		panic("KSUID set iterator is reading malformed data")
 | |
| 	}
 | |
| 
 | |
| 	return true
 | |
| }
 |