Function avalanche_types::hash::sha256
source · 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
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(())
}