Function avalanche_types::hash::sha256

source ·
pub fn sha256(d: impl AsRef<[u8]>) -> Vec<u8> 
Expand description

Returns SHA256 digest of the given data.

Examples found in repository?
src/ids/mod.rs (line 66)
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    pub fn sha256(d: impl AsRef<[u8]>) -> Self {
        Id::from_slice(&hash::sha256(d))
    }

    /// If the passed array is shorter than the LEN,
    /// it fills in with zero.
    pub fn from_slice(d: &[u8]) -> Self {
        assert!(d.len() <= LEN);
        let mut d: Vec<u8> = Vec::from(d);
        if d.len() < LEN {
            d.resize(LEN, 0);
        }
        let d: [u8; LEN] = d.try_into().unwrap();
        Id(d)
    }

    /// ref. "ids.ID.Prefix(output_index)"
    pub fn prefix(&self, prefixes: &[u64]) -> io::Result<Self> {
        let n = prefixes.len() + packer::U64_LEN + 32;
        let packer = packer::Packer::new(n, n);
        for pfx in prefixes {
            packer.pack_u64(*pfx)?;
        }
        packer.pack_bytes(&self.0)?;

        let b = packer.take_bytes();
        let d = hash::sha256(&b);
        Ok(Self::from_slice(&d))
    }
More examples
Hide additional examples
src/txs/raw.rs (line 40)
39
40
41
42
43
    fn cmp(&self, other: &Data) -> Ordering {
        let h1 = hash::sha256(&self.0);
        let h2 = hash::sha256(&other.0);
        h1.cmp(&(h2))
    }
src/txs/mod.rs (line 506)
505
506
507
508
509
510
511
512
513
    pub fn new(tx_bytes_with_no_signature: &[u8], tx_bytes_with_signatures: &[u8]) -> Self {
        let id = hash::sha256(tx_bytes_with_signatures);
        let id = ids::Id::from_slice(&id);
        Self {
            id,
            tx_bytes_with_no_signature: Vec::from(tx_bytes_with_no_signature),
            tx_bytes_with_signatures: Vec::from(tx_bytes_with_signatures),
        }
    }
src/formatting/mod.rs (line 14)
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
pub fn encode_cb58_with_checksum_string(d: &[u8]) -> String {
    // "hashing.Checksum" of "sha256.Sum256"
    let checksum = hash::sha256(d);
    let checksum_length = checksum.len();
    let checksum = &checksum[checksum_length - CHECKSUM_LENGTH..];

    let mut checked = d.to_vec();
    let mut checksum = checksum.to_vec();
    checked.append(&mut checksum);

    // ref. "utils/formatting encode.CB58"
    // ref. "base58.Encode"
    bs58::encode(&checked).into_string()
}

/// Implements "formatting.EncodeWithChecksum" with "formatting.CB58".
/// "ids.ShortID.String" appends checksum to the digest bytes.
/// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/formatting#EncodeWithChecksum>
/// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/hashing#Checksum>
pub fn encode_cb58_with_checksum_vec(d: &[u8]) -> Vec<u8> {
    // "hashing.Checksum" of "sha256.Sum256"
    let checksum = hash::sha256(d);
    let checksum_length = checksum.len();
    let checksum = &checksum[checksum_length - CHECKSUM_LENGTH..];

    let mut checked = d.to_vec();
    let mut checksum = checksum.to_vec();
    checked.append(&mut checksum);

    // ref. "utils/formatting encode.CB58"
    // ref. "base58.Encode"
    bs58::encode(&checked).into_vec()
}

/// Implements "formatting.Decode" with "formatting.CB58".
/// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/formatting#Decode
pub fn decode_cb58_with_checksum(d: &str) -> io::Result<Vec<u8>> {
    let decoded = match bs58::decode(d).into_vec() {
        Ok(v) => v,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                format!("failed to decode base58 ({})", e),
            ));
        }
    };
    let decoded_length = decoded.len();

    // verify checksum
    let checksum = &decoded[decoded_length - CHECKSUM_LENGTH..];
    let orig = &decoded[..decoded_length - CHECKSUM_LENGTH];

    // "hashing.Checksum" of "sha256.Sum256"
    let orig_checksum = hash::sha256(orig);
    let orig_checksum_length = orig_checksum.len();
    let orig_checksum = &orig_checksum[orig_checksum_length - CHECKSUM_LENGTH..];
    if !cmp_manager::eq_vectors(checksum, orig_checksum) {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            format!("invalid checksum {:?} != {:?}", checksum, orig_checksum),
        ));
    }

    Ok(orig.to_vec())
}

/// RUST_LOG=debug cargo test --package avalanche-types --lib -- formatting::test_encode_c58_with_checksum --exact --show-output
#[test]
fn test_encode_c58_with_checksum() {
    // ref. https://github.com/ava-labs/avalanchego/blob/v1.7.5/utils/formatting/encoding_test.go#L71
    let d: Vec<u8> = Vec::new();
    let hashed = encode_cb58_with_checksum_string(&d);
    assert_eq!(hashed, "45PJLL");
    let decoded = decode_cb58_with_checksum(&hashed).unwrap();
    assert_eq!(d, decoded);

    let d: Vec<u8> = vec![0];
    let hashed = encode_cb58_with_checksum_string(&d);
    assert_eq!(hashed, "1c7hwa");
    let decoded = decode_cb58_with_checksum(&hashed).unwrap();
    assert_eq!(d, decoded);

    let d: Vec<u8> = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255];
    let hashed = encode_cb58_with_checksum_string(&d);
    assert_eq!(hashed, "1NVSVezva3bAtJesnUj");
    let decoded = decode_cb58_with_checksum(&hashed).unwrap();
    assert_eq!(d, decoded);

    let d: Vec<u8> = vec![
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
        26, 27, 28, 29, 30, 31, 32,
    ];
    let hashed = encode_cb58_with_checksum_string(&d);
    assert_eq!(hashed, "SkB92YpWm4Q2ijQHH34cqbKkCZWszsiQgHVjtNeFF2HdvDQU");
    let decoded = decode_cb58_with_checksum(&hashed).unwrap();
    assert_eq!(d, decoded);
}

/// Implements "formatting.EncodeWithChecksum" with "formatting.Hex".
/// "ids.ShortID.String" appends checksum to the digest bytes.
/// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/formatting#EncodeWithChecksum>
/// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/hashing#Checksum>
pub fn encode_hex_with_checksum(d: &[u8]) -> String {
    // "hashing.Checksum" of "sha256.Sum256"
    let checksum = hash::sha256(d);
    let checksum_length = checksum.len();
    let checksum = &checksum[checksum_length - CHECKSUM_LENGTH..];

    let mut checked = d.to_vec();
    let mut checksum = checksum.to_vec();
    checked.append(&mut checksum);

    hex::encode(&checked)
}

/// Implements "formatting.Decode" with "formatting.Hex".
/// ref. <https://pkg.go.dev/github.com/ava-labs/avalanchego/utils/formatting#Decode>
pub fn decode_hex_with_checksum(d: &[u8]) -> io::Result<Vec<u8>> {
    let decoded = match hex::decode(d) {
        Ok(v) => v,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                format!("failed to decode base58 ({})", e),
            ));
        }
    };
    let decoded_length = decoded.len();

    // verify checksum
    let checksum = &decoded[decoded_length - CHECKSUM_LENGTH..];
    let orig = &decoded[..decoded_length - CHECKSUM_LENGTH];

    // "hashing.Checksum" of "sha256.Sum256"
    let orig_checksum = hash::sha256(orig);
    let orig_checksum_length = orig_checksum.len();
    let orig_checksum = &orig_checksum[orig_checksum_length - CHECKSUM_LENGTH..];
    if !cmp_manager::eq_vectors(checksum, orig_checksum) {
        return Err(Error::new(
            ErrorKind::InvalidInput,
            format!("invalid checksum {:?} != {:?}", checksum, orig_checksum),
        ));
    }

    Ok(orig.to_vec())
}
src/hash/mod.rs (line 35)
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
pub fn sha256_ripemd160<B>(b: B) -> io::Result<Vec<u8>>
where
    B: AsRef<[u8]>,
{
    let digest_sha256 = sha256(b);

    // "hashing.PubkeyBytesToAddress"
    // acquire hash digest in the form of GenericArray,
    // which in this case is equivalent to [u8; 20]
    // already in "type ShortID [20]byte" format
    let sha256_ripemd160 = Ripemd160::digest(&digest_sha256);

    // "ids.ToShortID" merely enforces "ripemd160" size!
    // ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/ids#ToShortID
    if sha256_ripemd160.len() != 20 {
        return Err(Error::new(
            ErrorKind::InvalidData,
            format!(
                "ripemd160 of sha256 must be 20-byte, got {}",
                sha256_ripemd160.len()
            ),
        ));
    }

    Ok(sha256_ripemd160.to_vec())
}
src/avm/txs/mod.rs (line 96)
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
    pub async fn sign<T: key::secp256k1::SignOnly>(
        &mut self,
        signers: Vec<Vec<T>>,
    ) -> io::Result<()> {
        // marshal "unsigned tx" with the codec version
        let type_id = Self::type_id();
        let packer = self.base_tx.pack(codec::VERSION, type_id)?;

        // "avalanchego" marshals the whole struct again for signed bytes
        // even when the underlying "unsigned_tx" is already once marshaled
        // ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/vms/avm/txs#Tx.SignSECP256K1Fx
        //
        // reuse the underlying packer to avoid marshaling the unsigned tx twice
        // just marshal the next fields in the struct and pack them all together
        // in the existing packer
        let tx_bytes_with_no_signature = packer.take_bytes();
        packer.set_bytes(&tx_bytes_with_no_signature);

        // compute sha256 for marshaled "unsigned tx" bytes
        // IMPORTANT: take the hash only for the type "avm.Tx" unsigned tx
        // not other fields -- only hash "avm.Tx.UnsignedTx" but not "avm.Tx.Creds"
        // ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/vms/avm#Tx
        let tx_bytes_hash = hash::sha256(&tx_bytes_with_no_signature);

        // number of of credentials
        let fx_creds_len = signers.len() as u32;
        // pack the second field in the struct
        packer.pack_u32(fx_creds_len)?;

        // sign the hash with the signers (in case of multi-sig)
        // and combine all signatures into a secp256k1fx credential
        self.fx_creds = Vec::new();
        for keys in signers.iter() {
            let mut sigs: Vec<Vec<u8>> = Vec::new();
            for k in keys.iter() {
                let sig = k.sign_digest(&tx_bytes_hash).await.map_err(|e| {
                    Error::new(ErrorKind::Other, format!("failed sign_digest {}", e))
                })?;
                sigs.push(Vec::from(sig));
            }

            let mut cred = key::secp256k1::txs::Credential::default();
            cred.signatures = sigs;

            let mut fx_cred = fx::Credential::default();
            fx_cred.cred = cred;

            // add a new credential to "Tx"
            self.fx_creds.push(fx_cred);
        }
        if fx_creds_len > 0 {
            // pack each "fx_cred" which is "secp256k1fx.Credential"
            // marshal type ID for "secp256k1fx.Credential"
            let cred_type_id = key::secp256k1::txs::Credential::type_id();
            for fx_cred in self.fx_creds.iter() {
                packer.pack_u32(cred_type_id)?;
                packer.pack_u32(fx_cred.cred.signatures.len() as u32)?;
                for sig in fx_cred.cred.signatures.iter() {
                    packer.pack_bytes(sig)?;
                }
            }
        }
        let tx_bytes_with_signatures = packer.take_bytes();
        let tx_id = hash::sha256(&tx_bytes_with_signatures);

        // update "BaseTx.Metadata" with id/unsigned bytes/bytes
        // ref. "avalanchego/vms/avm.Tx.SignSECP256K1Fx"
        // ref. "avalanchego/vms/components/avax.BaseTx.Metadata.Initialize"
        self.base_tx.metadata = Some(txs::Metadata {
            id: ids::Id::from_slice(&tx_id),
            tx_bytes_with_no_signature: tx_bytes_with_no_signature.to_vec(),
            tx_bytes_with_signatures: tx_bytes_with_signatures.to_vec(),
        });

        Ok(())
    }