Skip to content

Commit 797f09b

Browse files
committed
sui-sdk-types: add doc comments for the top-level and Address
1 parent 9e4be95 commit 797f09b

File tree

4 files changed

+245
-18
lines changed

4 files changed

+245
-18
lines changed

crates/sui-sdk-types/src/address.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,58 @@
1+
/// Unique identifier for an Account on the Sui blockchain.
2+
///
3+
/// An `Address` is a 32-byte pseudonymous identifier used to uniquely identify an account and
4+
/// asset-ownership on the Sui blockchain. Often, human-readable addresses are encoded in
5+
/// hexadecimal with a `0x` prefix. For example, this is a valid Sui address:
6+
/// `0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331`.
7+
///
8+
/// ```
9+
/// use sui_sdk_types::Address;
10+
///
11+
/// let hex = "0x02a212de6a9dfa3a69e22387acfbafbb1a9e591bd9d636e7895dcfc8de05f331";
12+
/// let address = Address::from_hex(hex).unwrap();
13+
/// println!("Address: {}", address);
14+
/// assert_eq!(hex, address.to_string());
15+
/// ```
16+
///
17+
/// # Deriving an Address
18+
///
19+
/// Addresses are cryptographically derived from a number of user account authenticators, the simplest
20+
/// of which is an [`Ed25519PublicKey`](crate::Ed25519PublicKey).
21+
///
22+
/// Deriving an address consists of the Blake2b256 hash of the sequence of bytes of its
23+
/// corresponding authenticator, prefixed with a domain-separator. For each authenticator, this
24+
/// domain-separator is the single byte-value of its [`SignatureScheme`](crate::SignatureScheme)
25+
/// flag. E.g. `hash(signature schema flag || authenticator bytes)`.
26+
///
27+
/// Each authenticator includes a convince method for deriving its `Address` as well as
28+
/// documentation for the specifics of how the derivation is done. See
29+
/// [`Ed25519PublicKey::derive_address`] for an example.
30+
///
31+
/// [`Ed25519PublicKey::derive_address`]: crate::Ed25519PublicKey::derive_address
32+
///
33+
/// ## Relationship to ObjectIds
34+
///
35+
/// [`ObjectId`]s and `Address`es share the same 32-byte addressable space but are derived
36+
/// leveraging different domain-separator values to ensure, cryptographically, that there won't be
37+
/// any overlap, e.g. there can't be a valid `Object` who's `ObjectId` is equal to that of the
38+
/// `Address` of a user account.
39+
///
40+
/// [`ObjectId`]: crate::ObjectId
41+
///
42+
/// # BCS
43+
///
44+
/// An `Address`'s BCS serialized form is simply the sequence of 32-bytes of the address.
45+
///
46+
/// ```
47+
/// use sui_sdk_types::Address;
48+
///
49+
/// let bytes = [
50+
/// 0x02, 0xa2, 0x12, 0xde, 0x6a, 0x9d, 0xfa, 0x3a, 0x69, 0xe2, 0x23, 0x87, 0xac, 0xfb, 0xaf,
51+
/// 0xbb, 0x1a, 0x9e, 0x59, 0x1b, 0xd9, 0xd6, 0x36, 0xe7, 0x89, 0x5d, 0xcf, 0xc8, 0xde, 0x05,
52+
/// 0xf3, 0x31,
53+
/// ];
54+
/// let address: Address = bcs::from_bytes(&bytes).unwrap();
55+
/// ```
156
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
257
#[cfg_attr(
358
feature = "serde",

crates/sui-sdk-types/src/crypto/zklogin.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,28 @@ pub struct CircomG1(pub [Bn254FieldElement; 3]);
6363
#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
6464
pub struct CircomG2(pub [[Bn254FieldElement; 2]; 3]);
6565

66-
/// A wrapper struct to retrofit in [enum PublicKey] for zkLogin.
67-
/// Useful to construct [struct MultiSigPublicKey].
66+
/// Public Key equivalent for Zklogin authenticators
67+
///
68+
/// A `ZkLoginPublicIdentifier` is the equivalent of a public key for other account authenticators,
69+
/// and contains the information required to derive the onchain account [`Address`] for a Zklogin
70+
/// authenticator.
71+
///
72+
/// ## Note
73+
///
74+
/// Due to a historical bug that was introduced in the Sui Typescript SDK when the zklogin
75+
/// authenticator was first introduced, there are now possibly two "valid" addresses for each
76+
/// zklogin authenticator depending on the bit-pattern of the `address_seed` value.
77+
///
78+
/// The original bug incorrectly derived a zklogin's address by stripping any leading
79+
/// zero-bytes that could have been present in the 32-byte length `address_seed` value prior to
80+
/// hashing, leading to a different derived address. This incorrectly derived address was
81+
/// presented to users of various wallets, leading them to sending funds to these addresses
82+
/// that they couldn't access. Instead of letting these users lose any assets that were sent to
83+
/// these addrsses, the Sui network decided to change the protocol to allow for a zklogin
84+
/// authenticator who's `address_seed` value had leading zero-bytes be authorized to sign for
85+
/// both the addresses derived from both the unpadded and padded `address_seed` value.
86+
///
87+
/// [`Address`]: crate::Address
6888
#[derive(Clone, Debug, PartialEq, Eq)]
6989
#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
7090
pub struct ZkLoginPublicIdentifier {

crates/sui-sdk-types/src/hash.rs

Lines changed: 112 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@ use blake2::Digest as DigestTrait;
55

66
type Blake2b256 = blake2::Blake2b<blake2::digest::consts::U32>;
77

8+
/// A Blake2b256 Hasher
89
#[derive(Debug, Default)]
910
pub struct Hasher(Blake2b256);
1011

1112
impl Hasher {
13+
/// Initialize a new Blake2b256 Hasher instance.
1214
pub fn new() -> Self {
1315
Self(Blake2b256::new())
1416
}
1517

18+
/// Process the provided data, updating internal state.
1619
pub fn update<T: AsRef<[u8]>>(&mut self, data: T) {
1720
self.0.update(data)
1821
}
1922

20-
/// Retrieve result and consume hasher instance.
23+
/// Finalize hashing, consuming the Hasher instance and returning the resultant hash or
24+
/// `Digest`.
2125
pub fn finalize(self) -> Digest {
2226
let mut buf = [0; Digest::LENGTH];
2327
let result = self.0.finalize();
@@ -27,6 +31,8 @@ impl Hasher {
2731
Digest::new(buf)
2832
}
2933

34+
/// Convenience function for creating a new Hasher instance, hashing the provided data, and
35+
/// returning the resultant `Digest`
3036
pub fn digest<T: AsRef<[u8]>>(data: T) -> Digest {
3137
let mut hasher = Self::new();
3238
hasher.update(data);
@@ -45,6 +51,28 @@ impl std::io::Write for Hasher {
4551
}
4652

4753
impl crate::Ed25519PublicKey {
54+
/// Derive an `Address` from this Public Key
55+
///
56+
/// An `Address` can be derived from an `Ed25519PublicKey` by hashing the bytes of the public
57+
/// key prefixed with the Ed25519 `SignatureScheme` flag (`0x00`).
58+
///
59+
/// `hash( 0x00 || 32-byte ed25519 public key)`
60+
///
61+
/// ```
62+
/// use sui_sdk_types::hash::Hasher;
63+
/// use sui_sdk_types::Address;
64+
/// use sui_sdk_types::Ed25519PublicKey;
65+
///
66+
/// let public_key_bytes = [0; 32];
67+
/// let mut hasher = Hasher::new();
68+
/// hasher.update([0x00]); // The SignatureScheme flag for Ed25519 is `0`
69+
/// hasher.update(public_key_bytes);
70+
/// let address = Address::new(hasher.finalize().into_inner());
71+
/// println!("Address: {}", address);
72+
///
73+
/// let public_key = Ed25519PublicKey::new(public_key_bytes);
74+
/// assert_eq!(address, public_key.derive_address());
75+
/// ```
4876
pub fn derive_address(&self) -> Address {
4977
let mut hasher = Hasher::new();
5078
self.write_into_hasher(&mut hasher);
@@ -59,6 +87,28 @@ impl crate::Ed25519PublicKey {
5987
}
6088

6189
impl crate::Secp256k1PublicKey {
90+
/// Derive an `Address` from this Public Key
91+
///
92+
/// An `Address` can be derived from a `Secp256k1PublicKey` by hashing the bytes of the public
93+
/// key prefixed with the Secp256k1 `SignatureScheme` flag (`0x01`).
94+
///
95+
/// `hash( 0x01 || 33-byte secp256k1 public key)`
96+
///
97+
/// ```
98+
/// use sui_sdk_types::hash::Hasher;
99+
/// use sui_sdk_types::Address;
100+
/// use sui_sdk_types::Secp256k1PublicKey;
101+
///
102+
/// let public_key_bytes = [0; 33];
103+
/// let mut hasher = Hasher::new();
104+
/// hasher.update([0x01]); // The SignatureScheme flag for Secp256k1 is `1`
105+
/// hasher.update(public_key_bytes);
106+
/// let address = Address::new(hasher.finalize().into_inner());
107+
/// println!("Address: {}", address);
108+
///
109+
/// let public_key = Secp256k1PublicKey::new(public_key_bytes);
110+
/// assert_eq!(address, public_key.derive_address());
111+
/// ```
62112
pub fn derive_address(&self) -> Address {
63113
let mut hasher = Hasher::new();
64114
self.write_into_hasher(&mut hasher);
@@ -73,6 +123,28 @@ impl crate::Secp256k1PublicKey {
73123
}
74124

75125
impl crate::Secp256r1PublicKey {
126+
/// Derive an `Address` from this Public Key
127+
///
128+
/// An `Address` can be derived from a `Secp256r1PublicKey` by hashing the bytes of the public
129+
/// key prefixed with the Secp256r1 `SignatureScheme` flag (`0x02`).
130+
///
131+
/// `hash( 0x02 || 33-byte secp256r1 public key)`
132+
///
133+
/// ```
134+
/// use sui_sdk_types::hash::Hasher;
135+
/// use sui_sdk_types::Address;
136+
/// use sui_sdk_types::Secp256r1PublicKey;
137+
///
138+
/// let public_key_bytes = [0; 33];
139+
/// let mut hasher = Hasher::new();
140+
/// hasher.update([0x02]); // The SignatureScheme flag for Secp256r1 is `2`
141+
/// hasher.update(public_key_bytes);
142+
/// let address = Address::new(hasher.finalize().into_inner());
143+
/// println!("Address: {}", address);
144+
///
145+
/// let public_key = Secp256r1PublicKey::new(public_key_bytes);
146+
/// assert_eq!(address, public_key.derive_address());
147+
/// ```
76148
pub fn derive_address(&self) -> Address {
77149
let mut hasher = Hasher::new();
78150
self.write_into_hasher(&mut hasher);
@@ -87,7 +159,11 @@ impl crate::Secp256r1PublicKey {
87159
}
88160

89161
impl crate::ZkLoginPublicIdentifier {
90-
/// Define as iss_bytes_len || iss_bytes || padded_32_byte_address_seed.
162+
/// Derive an `Address` from this `ZkLoginPublicIdentifier` by hashing the byte length of the
163+
/// `iss` followed by the `iss` bytes themselves and the full 32 byte `address_seed` value, all
164+
/// prefixed with the zklogin `SignatureScheme` flag (`0x05`).
165+
///
166+
/// `hash( 0x05 || iss_bytes_len || iss_bytes || 32_byte_address_seed )`
91167
pub fn derive_address_padded(&self) -> Address {
92168
let mut hasher = Hasher::new();
93169
self.write_into_hasher_padded(&mut hasher);
@@ -102,7 +178,11 @@ impl crate::ZkLoginPublicIdentifier {
102178
hasher.update(self.address_seed().padded());
103179
}
104180

105-
/// Define as iss_bytes_len || iss_bytes || unpadded_32_byte_address_seed.
181+
/// Derive an `Address` from this `ZkLoginPublicIdentifier` by hashing the byte length of the
182+
/// `iss` followed by the `iss` bytes themselves and the `address_seed` bytes with any leading
183+
/// zero-bytes stripped, all prefixed with the zklogin `SignatureScheme` flag (`0x05`).
184+
///
185+
/// `hash( 0x05 || iss_bytes_len || iss_bytes || unpadded_32_byte_address_seed )`
106186
pub fn derive_address_unpadded(&self) -> Address {
107187
let mut hasher = Hasher::new();
108188
hasher.update([self.scheme().to_u8()]);
@@ -134,6 +214,13 @@ impl crate::ZkLoginPublicIdentifier {
134214
}
135215

136216
impl crate::PasskeyPublicKey {
217+
/// Derive an `Address` from this Passkey Public Key
218+
///
219+
/// An `Address` can be derived from a `PasskeyPublicKey` by hashing the bytes of the
220+
/// `Secp256r1PublicKey` that corresponds to this passkey prefixed with the Passkey
221+
/// `SignatureScheme` flag (`0x06`).
222+
///
223+
/// `hash( 0x06 || 33-byte secp256r1 public key)`
137224
pub fn derive_address(&self) -> Address {
138225
let mut hasher = Hasher::new();
139226
self.write_into_hasher(&mut hasher);
@@ -148,14 +235,23 @@ impl crate::PasskeyPublicKey {
148235
}
149236

150237
impl crate::MultisigCommittee {
151-
/// Derive an Address from a MultisigCommittee. A MultiSig address
152-
/// is defined as the 32-byte Blake2b hash of serializing the flag, the
153-
/// threshold, concatenation of all n flag, public keys and
154-
/// its weight. `flag_MultiSig || threshold || flag_1 || pk_1 || weight_1
155-
/// || ... || flag_n || pk_n || weight_n`.
238+
/// Derive an `Address` from this MultisigCommittee.
239+
///
240+
/// A MultiSig address
241+
/// is defined as the 32-byte Blake2b hash of serializing the `SignatureScheme` flag (0x03), the
242+
/// threshold (in little endian), and the concatenation of all n flag, public keys and
243+
/// its weight.
244+
///
245+
/// `hash(0x03 || threshold || flag_1 || pk_1 || weight_1
246+
/// || ... || flag_n || pk_n || weight_n)`.
247+
///
248+
/// When flag_i is ZkLogin, the pk_i for the [`ZkLoginPublicIdentifier`] refers to the same
249+
/// input used when deriving the address using the
250+
/// [`ZkLoginPublicIdentifier::derive_address_padded`] method (using the full 32-byte
251+
/// `address_seed` value).
156252
///
157-
/// When flag_i is ZkLogin, pk_i refers to [struct ZkLoginPublicIdentifier]
158-
/// derived from padded address seed in bytes and iss.
253+
/// [`ZkLoginPublicIdentifier`]: crate::ZkLoginPublicIdentifier
254+
/// [`ZkLoginPublicIdentifier::derive_address_padded`]: crate::ZkLoginPublicIdentifier::derive_address_padded
159255
pub fn derive_address(&self) -> Address {
160256
use crate::MultisigMemberPublicKey::*;
161257

@@ -198,6 +294,9 @@ mod type_digest {
198294
use crate::TransactionEventsDigest;
199295

200296
impl Object {
297+
/// Calculate the digest of this `Object`
298+
///
299+
/// This is done by hashing the BCS bytes of this `Object` prefixed
201300
pub fn digest(&self) -> ObjectDigest {
202301
const SALT: &str = "Object::";
203302
let digest = type_digest(SALT, self);
@@ -298,9 +397,9 @@ mod signing_message {
298397
}
299398
}
300399

301-
/// A 1-byte domain separator for hashing Object ID in Sui. It is starting from 0xf0
302-
/// to ensure no hashing collision for any ObjectId vs Address which is derived
303-
/// as the hash of `flag || pubkey`.
400+
/// A 1-byte domain separator for deriving `ObjectId`s in Sui. It is starting from `0xf0` to ensure
401+
/// no hashing collision for any ObjectId vs Address which is derived as the hash of `flag ||
402+
/// pubkey`.
304403
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
305404
#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
306405
#[repr(u8)]

crates/sui-sdk-types/src/lib.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,57 @@
11
#![cfg_attr(doc_cfg, feature(doc_cfg))]
22

3-
#[cfg(feature = "hash")]
4-
#[cfg_attr(doc_cfg, doc(cfg(feature = "hash")))]
5-
pub mod hash;
3+
//! Core type definitions for the [Sui] blockchain.
4+
//!
5+
//! [Sui] is a next-generation smart contract platform with high throughput, low latency, and an
6+
//! asset-oriented programming model powered by the Move programming language. This crate provides
7+
//! type definitions for working with the data that makes up the [Sui] blockchain.
8+
//!
9+
//! [Sui]: https://sui.io
10+
//!
11+
//! # BCS
12+
//!
13+
//! [BCS] is the serialization format used to represent the state of the blockchain and is used
14+
//! extensively throughout the Sui ecosystem. In particular the BCS format is leveraged because it
15+
//! _"guarantees canonical serialization, meaning that for any given data type, there is a
16+
//! one-to-one correspondence between in-memory values and valid byte representations."_ One
17+
//! benefit of this property of having a canonical serialized representation is to allow different
18+
//! entities in the ecosystem to all agree on how a particular type should be interpreted and more
19+
//! importantly define a deterministic representation for hashing and signing.
20+
//!
21+
//! This library strives to guarantee that the types defined are fully BCS-compatible with the data
22+
//! that the network produces. The one caveat to this would be that as the Sui protocol evolves,
23+
//! new type variants are added and older versions of this library may not support those newly
24+
//! added variants. The expectation is that the most recent release of this library will support
25+
//! new variants and types as they are released to Sui's `testnet` network.
26+
//!
27+
//! See the documentation for the various types defined by this crate for an example of their BCS
28+
//! serialized representation. In addition to the format itself, some types have an extra layer of
29+
//! verification and may impose additional restrictions on valid byte representations above and
30+
//! beyond those already provided by BCS. In these instances the documentation for those types will
31+
//! clearly specify these additional restrictions.
32+
//!
33+
//! [BCS]: https://docs.rs/bcs
34+
//!
35+
//! # Feature flags
36+
//!
37+
//! This library uses a set of [feature flags] to reduce the number of dependencies and amount of
38+
//! compiled code. By default, no features are enabled which allows one to enable a subset
39+
//! specifically for their use case. Below is a list of the available feature flags.
40+
//!
41+
//! - `serde`: Enables support for serializing and deserializing types to/from BCS utilizing
42+
//! [serde] library.
43+
//! - `rand`: Enables support for generating random instances of a number of types via the [rand]
44+
//! library.
45+
//! - `hash`: Enables support for hashing, which is required for deriving addresses and calculating
46+
//! digests for various types.
47+
//! - `proptest`: Enables support for the [proptest] library by providing implementations of
48+
//! [proptest::arbitrary::Arbitrary] for many types.
49+
//!
50+
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
51+
//! [serde]: https://docs.rs/serde
52+
//! [rand]: https://docs.rs/rand
53+
//! [proptest]: https://docs.rs/proptest
54+
//! [proptest::arbitrary::Arbitrary]: https://docs.rs/proptest/latest/proptest/arbitrary/trait.Arbitrary.html
655
756
mod address;
857
mod checkpoint;
@@ -19,6 +68,10 @@ mod transaction;
1968
mod type_tag;
2069
mod u256;
2170

71+
#[cfg(feature = "hash")]
72+
#[cfg_attr(doc_cfg, doc(cfg(feature = "hash")))]
73+
pub mod hash;
74+
2275
pub use address::Address;
2376
pub use address::AddressParseError;
2477
pub use checkpoint::CheckpointCommitment;

0 commit comments

Comments
 (0)