pub struct Right {
pub id: RightId,
pub commitment: Hash,
pub owner: OwnershipProof,
pub salt: Vec<u8>,
pub nullifier: Option<Hash>,
pub state_root: Option<Hash>,
pub execution_proof: Option<Vec<u8>>,
}Expand description
A consumable Right in the USP system.
Every chain enforces single-use of Rights, but at different enforcement levels (L1 Structural → L2 Type-Enforced → L3 Cryptographic).
The chain provides the minimum guarantee (single-use enforcement). Clients verify everything else.
Fields§
§id: RightIdUnique identifier: H(commitment || salt)
commitment: HashEncodes the state + rules of this Right
owner: OwnershipProofProof of ownership
salt: Vec<u8>Salt used to compute the Right ID. Stored to enable ID recomputation during deserialization.
nullifier: Option<Hash>One-time consumption marker (L3+ only)
L1 (Bitcoin/Sui): None — chain enforces structurally. L2 (Aptos): None — Move VM enforces non-duplication. L3 (Ethereum): Some — nullifier registered in contract.
state_root: Option<Hash>Off-chain state commitment root
Commits to the full state history for this Right. Clients use this to verify state transitions without fetching the entire history on every validation.
execution_proof: Option<Vec<u8>>Optional execution proof (ZK, fraud proof, etc.)
For advanced use cases where the Right’s execution needs to be proven without revealing its contents.
Implementations§
Source§impl Right
impl Right
Sourcepub fn new(commitment: Hash, owner: OwnershipProof, salt: &[u8]) -> Self
pub fn new(commitment: Hash, owner: OwnershipProof, salt: &[u8]) -> Self
Create a new Right with the given parameters.
The Right ID is deterministically computed from the commitment and salt, ensuring uniqueness even for duplicate commitments.
Sourcepub fn consume(
&mut self,
secret: Option<&[u8]>,
chain_context: Option<&[u8; 32]>,
) -> Option<Hash>
pub fn consume( &mut self, secret: Option<&[u8]>, chain_context: Option<&[u8; 32]>, ) -> Option<Hash>
Mark this Right as consumed by setting the nullifier.
§Enforcement Level
-
L1 (Bitcoin/Sui): This method is a local marker only. The actual single-use enforcement is done by the chain (UTXO spending / Object deletion).
-
L2 (Aptos): This method is a local marker only. The Move VM enforces non-duplication of resources.
-
L3 (Ethereum): The nullifier MUST be registered on-chain. The contract’s
nullifiers[id] = trueis what enforces single-use.
§Nullifier Construction
nullifier = tagged_hash("csv-nullifier", right_id || secret || context)
Where context = H(chain_id || domain_separator) binds the nullifier
to a specific chain context, preventing cross-chain replay attacks
even if the same secret is reused.
§Arguments
secret— The user’s secret (prevents front-running)chain_context— Pre-computed context hash:H(chain_id || domain_separator)
§Returns
The nullifier hash, or None for L1/L2 chains where the
nullifier is not needed (but returned for local tracking).
Sourcepub fn transfer(&self, new_owner: OwnershipProof, transfer_salt: &[u8]) -> Right
pub fn transfer(&self, new_owner: OwnershipProof, transfer_salt: &[u8]) -> Right
Transfer this Right to a new owner.
Creates a new Right with the same commitment and state but different ownership. The original Right remains valid until explicitly consumed.
§Arguments
new_owner- The new owner’s ownership prooftransfer_salt- A unique salt for the transfer to ensure unique ID
§Returns
A new Right instance with the new owner and a fresh ID
Sourcepub fn verify(&self) -> Result<(), RightError>
pub fn verify(&self) -> Result<(), RightError>
Verify this Right’s ownership and validity.
This is the core client-side validation function. It checks:
- The ownership proof is cryptographically valid
- The Right ID is correctly derived from commitment || salt
- The commitment is well-formed
- The Right has not been consumed (nullifier not set)
For full consignment validation, use the client-side validation engine (Sprint 2).
Sourcepub fn to_canonical_bytes(&self) -> Vec<u8> ⓘ
pub fn to_canonical_bytes(&self) -> Vec<u8> ⓘ
Serialize this Right to canonical bytes.
Used for hashing, signing, and transmission.
Sourcepub fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, RightError>
pub fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, RightError>
Deserialize a Right from canonical bytes.
§Errors
Returns RightError::InvalidEncoding if the bytes are malformed.
Sourcepub fn is_consumed(&self) -> bool
pub fn is_consumed(&self) -> bool
Check if this Right has been consumed.
Sourcepub fn requires_nullifier(&self) -> bool
pub fn requires_nullifier(&self) -> bool
Get the chain enforcement level indicator.
Returns true if this is an L3 (cryptographic) Right that requires
nullifier tracking.