|
| 1 | +package nonffi |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "math/bits" |
| 6 | + |
| 7 | + "github.com/filecoin-project/go-commp-utils/zerocomm" |
| 8 | + commcid "github.com/filecoin-project/go-fil-commcid" |
| 9 | + "github.com/filecoin-project/go-state-types/abi" |
| 10 | + "github.com/ipfs/go-cid" |
| 11 | + sha256simd "github.com/minio/sha256-simd" |
| 12 | +) |
| 13 | + |
| 14 | +func GenerateUnsealedCID(proofType abi.RegisteredSealProof, pieces []abi.PieceInfo) (cid.Cid, error) { |
| 15 | + spi, found := abi.SealProofInfos[proofType] |
| 16 | + if !found { |
| 17 | + return cid.Undef, fmt.Errorf("unknown seal proof type %d", proofType) |
| 18 | + } |
| 19 | + |
| 20 | + target := abi.PaddedPieceSize(spi.SectorSize) |
| 21 | + if len(pieces) == 0 { |
| 22 | + return zerocomm.ZeroPieceCommitment(target.Unpadded()), nil |
| 23 | + } |
| 24 | + |
| 25 | + // sancheck everything |
| 26 | + for i, p := range pieces { |
| 27 | + if p.Size < 128 { |
| 28 | + return cid.Undef, fmt.Errorf("invalid Size of PieceInfo %d: value %d is too small", i, p.Size) |
| 29 | + } |
| 30 | + if pieces[i].Size > target { |
| 31 | + return cid.Undef, fmt.Errorf("invalid Size of PieceInfo %d: value %d is larger than sector size of SealProofType %d", i, p.Size, proofType) |
| 32 | + } |
| 33 | + if bits.OnesCount64(uint64(p.Size)) != 1 { |
| 34 | + return cid.Undef, fmt.Errorf("invalid Size of PieceInfo %d: value %d is not a power of 2", i, p.Size) |
| 35 | + } |
| 36 | + if _, err := commcid.CIDToPieceCommitmentV1(p.PieceCID); err != nil { |
| 37 | + return cid.Undef, fmt.Errorf("invalid PieceCid for PieceInfo %d: %w", i, err) |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | + // reimplement https://github.com/filecoin-project/rust-fil-proofs/blob/380d6437c2/filecoin-proofs/src/pieces.rs#L85-L145 |
| 42 | + stack := append( |
| 43 | + make([]abi.PieceInfo, 0, 32), |
| 44 | + pieces[0], |
| 45 | + ) |
| 46 | + |
| 47 | + for i := 1; i < len(pieces); i++ { |
| 48 | + |
| 49 | + for stack[len(stack)-1].Size < pieces[i].Size { |
| 50 | + lastSize := stack[len(stack)-1].Size |
| 51 | + |
| 52 | + stack = reduceStack( |
| 53 | + append( |
| 54 | + stack, |
| 55 | + abi.PieceInfo{ |
| 56 | + Size: lastSize, |
| 57 | + PieceCID: zerocomm.ZeroPieceCommitment(lastSize.Unpadded()), |
| 58 | + }, |
| 59 | + ), |
| 60 | + ) |
| 61 | + } |
| 62 | + |
| 63 | + stack = reduceStack( |
| 64 | + append( |
| 65 | + stack, |
| 66 | + pieces[i], |
| 67 | + ), |
| 68 | + ) |
| 69 | + } |
| 70 | + |
| 71 | + for len(stack) > 1 || stack[0].Size < target { |
| 72 | + lastSize := stack[len(stack)-1].Size |
| 73 | + stack = reduceStack( |
| 74 | + append( |
| 75 | + stack, |
| 76 | + abi.PieceInfo{ |
| 77 | + Size: lastSize, |
| 78 | + PieceCID: zerocomm.ZeroPieceCommitment(lastSize.Unpadded()), |
| 79 | + }, |
| 80 | + ), |
| 81 | + ) |
| 82 | + } |
| 83 | + |
| 84 | + if stack[0].Size > target { |
| 85 | + return cid.Undef, fmt.Errorf("provided pieces sum up to %d bytes, which is larger than sector size of SealProofType %d", stack[0].Size, proofType) |
| 86 | + } |
| 87 | + |
| 88 | + return stack[0].PieceCID, nil |
| 89 | +} |
| 90 | + |
| 91 | +var s256 = sha256simd.New() |
| 92 | + |
| 93 | +func reduceStack(s []abi.PieceInfo) []abi.PieceInfo { |
| 94 | + for { |
| 95 | + if len(s) < 2 || s[len(s)-2].Size != s[len(s)-1].Size { |
| 96 | + break |
| 97 | + } |
| 98 | + |
| 99 | + l, _ := commcid.CIDToPieceCommitmentV1(s[len(s)-2].PieceCID) |
| 100 | + r, _ := commcid.CIDToPieceCommitmentV1(s[len(s)-1].PieceCID) |
| 101 | + s256.Reset() |
| 102 | + s256.Write(l) |
| 103 | + s256.Write(r) |
| 104 | + d := s256.Sum(make([]byte, 0, 32)) |
| 105 | + d[31] &= 0b00111111 |
| 106 | + newPiece, _ := commcid.PieceCommitmentV1ToCID(d) |
| 107 | + |
| 108 | + s[len(s)-2] = abi.PieceInfo{ |
| 109 | + Size: 2 * s[len(s)-2].Size, |
| 110 | + PieceCID: newPiece, |
| 111 | + } |
| 112 | + |
| 113 | + s = s[:len(s)-1] |
| 114 | + } |
| 115 | + |
| 116 | + return s |
| 117 | +} |
0 commit comments