Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

frc(0069): change v2 piece multihashes to enable arbitrarily sized data #808

42 changes: 33 additions & 9 deletions FRCs/frc-0069.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ created: 2023-07-26

## Simple Summary
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of which version of the Simple Summary is merged by the author, can we add a few extra words about why this alternative CID representation is being introduced? What functionality or improvement does it support?


Introduces an alternative CID representation for the FR32 padded sha256-trunc254-padded binary merkle trees used in Filecoin Piece Commitments (i.e. CommP). In it we use the [Raw codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L41) and a new [sha2-256-trunc254-padded-binary-tree multihash (or piece multihash)](https://link.tld) rather than the [Fil-commitment-unsealed codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L517) and the [sha2-256-trunc254-padded multihash](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L149).
Introduces an alternative CID representation for the FR32 padded sha256-trunc254-padded binary merkle trees used in Filecoin Piece Commitments (i.e. CommP). In it we use the [Raw codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L41) and a new [sha2-256-trunc254-padded-binary-tree multihash (or piece multihash)](https://github.com/multiformats/multicodec/pull/331) rather than the [Fil-commitment-unsealed codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L517) and the [sha2-256-trunc254-padded multihash](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L149).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe?

Suggested change
Introduces an alternative CID representation for the FR32 padded sha256-trunc254-padded binary merkle trees used in Filecoin Piece Commitments (i.e. CommP). In it we use the [Raw codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L41) and a new [sha2-256-trunc254-padded-binary-tree multihash (or piece multihash)](https://github.com/multiformats/multicodec/pull/331) rather than the [Fil-commitment-unsealed codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L517) and the [sha2-256-trunc254-padded multihash](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L149).
Introduces an alternative CID representation for the FR32 padded sha256-trunc254-padded binary merkle trees used in Filecoin Piece Commitments (i.e. CommP). In it we use the [Raw codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L41) and a new [sha2-256-trunc254-padbintree multihash (or piece multihash)](https://github.com/multiformats/multicodec/pull/331) rather than the [Fil-commitment-unsealed codec](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L517) and the [sha2-256-trunc254-padded multihash](https://github.com/multiformats/multicodec/blob/566eaf857a9d20573d3910221db7b34d98e8a0fc/table.csv#L149).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with this. Any objections?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not eager to change lib names but ok if it's a must. publishing packages with last name triggered npm's spam filter so I had to email etc... I suspect same will happen with this name also.



## Abstract
Expand All @@ -24,7 +24,7 @@ For example, in much of the relevant portions of the Filecoin spec and lotus' Go

This makes it much more natural to work with new concepts like [Deal Aggregates](https://pkg.go.dev/github.com/filecoin-project/[email protected]/datasegment#NewAggregate), as proposed in [FRC-0058](https://github.com/filecoin-project/FIPs/blob/7e499523c9c7ed2c48c6a36967f7f011cee1fefd/FRCs/frc-0058.md).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This makes it much more natural to work with new concepts like [Deal Aggregates](https://pkg.go.dev/github.com/filecoin-project/[email protected]/datasegment#NewAggregate), as proposed in [FRC-0058](https://github.com/filecoin-project/FIPs/blob/7e499523c9c7ed2c48c6a36967f7f011cee1fefd/FRCs/frc-0058.md).
The proposed V2 multihash makes it easier to work with new concepts like [Deal Aggregates](https://pkg.go.dev/github.com/filecoin-project/[email protected]/datasegment#NewAggregate), as proposed in [FRC-0058](https://github.com/filecoin-project/FIPs/blob/7e499523c9c7ed2c48c6a36967f7f011cee1fefd/FRCs/frc-0058.md).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, but the use of the word "concepts" in the above sentence could also benefit from specification. Is it possible to do so? Perhaps "unstructured", "variably sized" or "large" data, etc., whatever is/may be accurate.


To resolve this we introduce a new multihash type [fr32-sha2-256-trunc254-padded-binary-tree multihash](https://link.tld) which combines the root hash with the tree height (which in the full and balanced binary trees used in Piece commitments is equivalent to size).
To resolve this we introduce a new multihash type [fr32-sha2-256-trunc254-padded-binary-tree multihash](https://github.com/multiformats/multicodec/pull/331) which combines the root hash with the tree height and the amount of padding of the data with zeros such that the result is a full and balanced binary tree after the fr32 padding is applied. If this multihash were to be used to reference the full piece as understood by the Filecoin on-chain consensus mechanism, this would involve the special case where a padding of zero is used.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm failing to understand the last sentence, what is that special case ? I think it would be a good idea if this was clear to someone like me who's not well versed in filecoin on-chain consensus mechanism or we simple have not mentioned it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was the earlier text better, or both confusing? Basically the idea is:

  1. that likely anything you see today as a v1 piece CID +size is logically the same as a v2 piece CID with the same size and no zero padding
    • IIUC the reason this is true is because people tend to see piece CIDs associated with deals and sectors where AFAIK there is basically no tooling around padding which is why there are various hacks like abusing a CARv1 section size being 0 as an EOF signal despite that not being something in the CAR spec.
  2. the thing that is technically proven by the Filecoin chain (and as a result is the thing people tend to see) is that the full binary tree has been stored (i.e. the user padding is, in the context of Filecoin consensus, basically just metadata with all the padding bytes being considered part of the stored data). @ribasushi had some concerns here around users understanding what is proven vs not which if I understood them correctly were captured here FRC: Piece Multihash CID #759 (reply in thread). I don't really understand why the difference is important, but I tried to capture that perspective in the linked discussion and allude to it here.

Suggestions welcome though

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a fun fact: Switching from a v1 piece CID to a v2 one (i.e. assuming zero padding) results in a piece CID that is exactly the same size.

  • v1: <0x01><codec = 3 bytes as varint><multihash = 2 bytes as varint><mh-digest-len = 1 byte><digest = 32 bytes> = 39 bytes
  • v2: <0x01><codec = 1 byte as varint><multihash = 2 bytes as varint><mh-digest-len=1 byte><padding=0x00><height = 1 byte><root-hash = 32 bytes> = 39 bytes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe?

Suggested change
To resolve this we introduce a new multihash type [fr32-sha2-256-trunc254-padded-binary-tree multihash](https://github.com/multiformats/multicodec/pull/331) which combines the root hash with the tree height and the amount of padding of the data with zeros such that the result is a full and balanced binary tree after the fr32 padding is applied. If this multihash were to be used to reference the full piece as understood by the Filecoin on-chain consensus mechanism, this would involve the special case where a padding of zero is used.
To satisfy this need we introduce a new multihash type [fr32-sha2-256-trunc254-padbintree multihash](https://github.com/multiformats/multicodec/pull/331) which prefixes the root hash with two values: 1) the required amount of `0x00` padding appended to the hashed payload such that the result is a full and balanced binary tree once the fr32 expansion is applied and 2) the height of the resulting binary tree comprised of 32-byte nodes. When used in the context of the Filecoin proving system, such a multihash can be directly translated to a [PieceInfo](https://pkg.go.dev/github.com/filecoin-project/go-state-types/abi#PieceInfo), and conversely any Filecoin [PieceInfo](https://pkg.go.dev/github.com/filecoin-project/go-state-types/abi#PieceInfo) struct can be losslessly expressed as a PieceCIDv2 with the padding value set to `0`.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ribasushi I think you meant "hash payload" and not "hashed payload" right ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

struct can be losslessly expressed as a PieceCIDv2 with the padding value set to 0

I think this is true, yet misleading. It is true you can translate PieceInfo to PieceCIDv2 but you can not do the reverse. Reading ☝️ leaves the impression that you can roundtrip, so I suggest to either rephrase it or at least call out no roundtrips explicitly to avoid confusion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ribasushi I think you meant "hash payload" and not "hashed payload" right ?

I meant hashed payload: the data (payload) that is to be hashed. We can switch to hashed data, it sounds clunkier to me...

struct can be losslessly expressed as a PieceCIDv2 with the padding value set to 0

s/losslessly/fully/ ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding comment here about line 21: it should mention payload size as well


## Specification

Expand All @@ -36,11 +36,25 @@ A CIDv1 requires a:

The core component introduce in this specification is a new multihash type fr32-sha2-256-trunc254-padded-binary-tree multihash.

The multihash code for this type is 0x1011 as identifier in the [multicodec code table](https://link.tld).
The multihash code for this type is 0x1011 as identified in the [multicodec code table](https://github.com/multiformats/multicodec/pull/331).

The digest for the multihash is 33 bytes. The first byte defines the height of the tree. For example if the first byte is 0 the tree is a single 32-byte leaf. Similarly, if the first byte is 30 then the tree is 30 levels deep which, since the leaves must be 32 bytes, represents a piece of size 32*2^30 bytes = 32GiB.
The digest for the multihash is a variable number of bytes.

Note that the data processed by this hash function must be of size `N = 2^i * 127/128` where `i` is any positive integer >=7 and <=255. This means that the minimum hashable amount of data is 127 bytes.
It can be roughly described as `uvarint padding | uint8 height | 32 byte root data` where `|` means concatenation.

- The first bytes are a [uvarint](https://github.com/multiformats/unsigned-varint) of the number of bytes needed to pad the underlying data such that after FR32 padding it will be a full binary tree
- If the data is < 127 bytes then it is padded to 127 bytes. For example, if the data is of size 12 the padding will be `127-12 = 115`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- If the data is < 127 bytes then it is padded to 127 bytes. For example, if the data is of size 12 the padding will be `127-12 = 115`
Due to the fr32 expansion mechanism, **if the input data size is < 127 bytes then it is padded to a size of 127 bytes**. For example, if the data is of size 12 the padding will be `127-12 = 115`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the "why" here necessary? I'm fine with it, but it's not strictly needed right? Nothing changes for us here if it was decided that fr32 allows padding up the last byte if the data isn't a multiple of 127 since this spec insists that it does.

Is the "why" here a placeholder for claiming that ground since there's no fr32 spec beyond the couple lines on specs.filecoin.io and those don't mention 127 bytes at all?

Comment on lines +45 to +46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • it's not padding, padding implies byte-work, fr32 is not that...
Suggested change
- The first bytes are a [uvarint](https://github.com/multiformats/unsigned-varint) of the number of bytes needed to pad the underlying data such that after FR32 padding it will be a full binary tree
- If the data is < 127 bytes then it is padded to 127 bytes. For example, if the data is of size 12 the padding will be `127-12 = 115`
- The first bytes are a [uvarint](https://github.com/multiformats/unsigned-varint) of the number of `0x00` bytes needed to pad the underlying data such that after FR32 expansion it will be a fully balanced binary tree. Due to the fr32 expansion mechanism, **if the input data size is < 127 bytes then it is padded to a size of 127 bytes**. That is, a CID with a certain padding value of `P` and a certain height (see next section) `H`, encodes an initial payload size of `( 1 << (H-2) ) * 127 - P`
- For example, if the data is of size 12 the padding will be `127-12 = 115`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it's worth I think formula should be (2 ^ (H-2)) * 127 - P I know it's the same, but this version does not require you to mentally do the translation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree that the mathier version is more natural here.

- For example, if the data is of size 254 (i.e. 2^i * 127/128, where i is a positive integer >= 7) then this will be 0
- For example, if the data is of size 256 then the padding is `508-256=252`
- Note: because the unsigned-varint spec currently has a maximum representable size of 2^63-1 (and 9 bytes to represent the varint) this puts a cap on the maximum size of data representable by this multihash as well
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we don't strictly need to follow the unsigned-varint spec here and have a maximum size it seems like a pretty reasonable thing to do. Any disagreement?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we deal with such large payloads so we're probably ok, but probably good to confirm with @ribasushi if that could be an issue elsewhere

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If your PieceCid describes something larger than 63 bits ( 8 EiB ), then the "actual payload size" becomes meaningless anyway, and you are in world with padding of 0 and height up to 127, which is about 1<<132 or... many many many HellaBytes

- Note: because this is padding data it must be less than the size of the underlying data (with the exception of data less than 127 bytes which is always padded up to 127 bytes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the ( 1 << (H-2) ) * 127 - P formula, is this sentence even needed...?

- The next byte defines the height of the tree
- For example if the first byte is 0 the tree is a single 32-byte node

- Similarly, if the first byte is 30 then the tree is 30 levels deep which, since the leaves must be 32 bytes, represents a piece of size 32*2^30 bytes = 32GiB.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Similarly, if the first byte is 30 then the tree is 30 levels deep which, since the leaves must be 32 bytes, represents a piece of size 32*2^30 bytes = 32GiB.
- Similarly, if the first byte is 30 then the tree is 30 levels deep which, since all nodes used by this hash are 32 bytes long, represents a piece of size 32*2^30 bytes = 32GiB.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the leaf nodes matter here. If the intermediate nodes were bigger than leaf nodes (e.g. if they'd included one extra byte flagging them as intermediate nodes 🙃) the data size would be unchanged.

- The last 32 bytes are the value at the root of the binary tree

Note: This structure is such that the last 33 bytes of the multihash are `uint 8 height | 32 byte root data` which is the data that the proofs underlying Filecoin consensus can attest to (i.e. the proofs don't know how much of the padding is padding vs zeros that are part of the user data).

### Raw codec

Expand All @@ -63,11 +77,21 @@ A tuple of (v1 Piece CID, Piece size) can be converted into a valid v2 Piece CID

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making a note about line 69: being able to convert between v1 and v2 Piece CIDs: one can not do that. You can downgrade a v2 to V1+Size, but as written it implies one can up-cast a V1 to a V2, like you can do a CidV0 to CidV1, which... nope.

## Test Cases

Take data of size 127*4 bytes where the first 127 bytes are 0, the next 127 are 1, the next 127 are 2, and the last 127 are 3. The v1 piece CID of this data would be `baga6ea4seaqes3nobte6ezpp4wqan2age2s5yxcatzotcvobhgcmv5wi2xh5mbi`. The multihash-based piece CID would be `bafkzcibbarew3lqmzhrgl37fuadoqbrguxofyqe6luyvlqjzqtfpnsgvz7lak`. With a base16 multibase this would be `f015591202104496dae0cc9e265efe5a006e80626a5dc5c409e5d3155c13984caf6c8d5cfd605` or equivalently (`(multibase = f) | (CIDv1 prefix = 0x01) | (Raw codec = 0x55) | (fr32-sha2-256-trunc254-padded-binary-tree multihash encoded varint = 0x9120) | (length of digest = 0x21) | (tree height = 0x04) | (underlying hash digest = 496...605)`)
Take data of size 127*4 bytes where the first 127 bytes are 0, the next 127 are 1, the next 127 are 2, and the last 127 are 3. The v1 piece CID of this data would be `baga6ea4seaqes3nobte6ezpp4wqan2age2s5yxcatzotcvobhgcmv5wi2xh5mbi`. The multihash-based piece CID would be `bafkzcibcaaces3nobte6ezpp4wqan2age2s5yxcatzotcvobhgcmv5wi2xh5mbi`. With a base16 multibase this would be `f01559120220004496dae0cc9e265efe5a006e80626a5dc5c409e5d3155c13984caf6c8d5cfd605` or equivalently (`(multibase = f) | (CIDv1 prefix = 0x01) | (Raw codec = 0x55) | (fr32-sha2-256-trunc254-padded-binary-tree multihash encoded varint = 0x9120) | (length of digest = 0x22) | (amount of data padding = 0x00) | (tree height = 0x04) | (underlying hash digest = 496...605)`)
Take payload of size 0 bytes. There MUST be `127` bytes of padding. The v2 piece CID MUST be `bafkzcibcp4bdomn3tgwgrh3g532zopskstnbrd2n3sxfqbze7rxt7vqn7veigmy`.

Take payload of 127 bytes where all bytes are 0. There MUST be `0` bytes of padding. The hight MUST be `2`. The v2 piece CID MUST be `bafkzcibcaabdomn3tgwgrh3g532zopskstnbrd2n3sxfqbze7rxt7vqn7veigmy`.

aschmahmann marked this conversation as resolved.
Show resolved Hide resolved
Take payload of 128 bytes where all bytes are 0. There MUST be `126` bytes of padding. The height MUST be `3`. The v2 piece CID MUST be `bafkzcibcpybwiktap34inmaex4wbs6cghlq5i2j2yd2bb2zndn5ep7ralzphkdy`
Given the piece CID v1 of the empty 32 GiB piece (i.e. 32 * 2^30 * 127/128 bytes of zeros)`baga6ea4seaqao7s73y24kcutaosvacpdjgfe5pw76ooefnyqw4ynr3d2y6x2mpq` the corresponding mutlihash piece CID would be `bafkzcibcaapao7s73y24kcutaosvacpdjgfe5pw76ooefnyqw4ynr3d2y6x2mpq`

Given the piece CID v1 of the empty 64 GiB piece (i.e. 64 * 2^30 * 127/128 bytes of zeros)`baga6ea4seaqomqafu276g53zko4k23xzh4h4uecjwicbmvhsuqi7o4bhthhm4aq` the corresponding piece mutlihash piece CID would be `bafkzcibcaap6mqafu276g53zko4k23xzh4h4uecjwicbmvhsuqi7o4bhthhm4aq`

Take data of size 127*8 bytes where the first where the first 127 bytes are 0, the next 127 are 1, the next 127 are 2, the next 127 are 3 and the remaining `127*4` bytes are 0. There is no padding so the v1 piece CID would be `baga6ea4seaqn42av3szurbbscwuu3zjssvfwbpsvbjf6y3tukvlgl2nf5rha6pa` and the v2 would be `bafkzcibcauan42av3szurbbscwuu3zjssvfwbpsvbjf6y3tukvlgl2nf5rha6pa`.

Given the piece CID v1 of the empty 32 GiB piece `baga6ea4seaqao7s73y24kcutaosvacpdjgfe5pw76ooefnyqw4ynr3d2y6x2mpq` the corresponding mutlihash piece CID would be `bafkzcibbdydx4x66gxcqveyduviaty2jrjhl5x7ttrbloefxgdmoy6whv6td4`
Take data of size 128*4 bytes where the first where the first 127 bytes are 0, the next 127 are 1, the next 127 are 2, the next 127 are 3 and the remaining 4 bytes are 0. There is `504` bytes of padding needed and so the v1 piece CID is `baga6ea4seaqn42av3szurbbscwuu3zjssvfwbpsvbjf6y3tukvlgl2nf5rha6pa` (notice it's the same as above) and the v2 is `bafkzcibd7abqlxticxolgseegik2stpfgkkuwyf6kufex3doorkvmzpjuxwe4dz4`.

Given the piece CID v1 of the empty 64 GiB piece `baga6ea4seaqomqafu276g53zko4k23xzh4h4uecjwicbmvhsuqi7o4bhthhm4aq` the corresponding piece mutlihash piece CID would be `bafkzcibbd7teabngx7rxo6ktxcww56j7b7fbasnsaqlfj4vech3xaj4zz3hae`
Take the data above and append one more zero (i.e. 127 0s, 127 1s, 127 2s, 127 3s, 5 0s). There are `503` bytes of padding needed and so the v1 piece CID is `baga6ea4seaqn42av3szurbbscwuu3zjssvfwbpsvbjf6y3tukvlgl2nf5rha6pa` (notice it's the same as above) and the v2 is `bafkzcibd64bqlxticxolgseegik2stpfgkkuwyf6kufex3doorkvmzpjuxwe4dz4`.

## Security Considerations
Does not impact core Filecoin security.
Expand All @@ -82,7 +106,7 @@ This also enables the use of IPFS-based tooling for moving around Pieces, with t

## Implementation

- There is a Go implementation in a [fork of go-fil-commcid](https://github.com/filecoin-project/go-fil-commcid/pull/5) which can get merged [upstream](https://github.com/filecoin-project/go-fil-commcid) upon acceptance of the FRC.
- There is a Go implementation in a [fork of go-fil-commcid](https://github.com/filecoin-project/go-fil-commcid/pull/6) which can get merged [upstream](https://github.com/filecoin-project/go-fil-commcid) upon acceptance of the FRC.
- There is a JavaScript implementation in https://github.com/web3-storage/data-segment/

## Copyright
Expand Down