From ae584078f298f895e6ff1587b321ae7c668e857f Mon Sep 17 00:00:00 2001 From: Julia Naomi Date: Mon, 14 Sep 2020 20:07:26 -0300 Subject: [PATCH] uses crc16-ccitt logic to create field crc16 --- Cargo.toml | 6 +++++- README.md | 9 ++++++++- benches/crc16.rs | 15 +++++++++++++++ src/aux.rs | 31 +++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/model.rs | 7 ++++--- tests/lib.rs | 13 +++++++++++++ 7 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 benches/crc16.rs diff --git a/Cargo.toml b/Cargo.toml index 16b3a6e..d6ceec7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "brcode" -version = "1.0.1" +version = "1.1.0" authors = ["Julia Naomi "] edition = "2018" description = "Crate to parse and emit BR Codes" @@ -37,4 +37,8 @@ harness = false [[bench]] name = "both_ways" +harness = false + +[[bench]] +name = "crc16" harness = false \ No newline at end of file diff --git a/README.md b/README.md index e323173..70b44fe 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,14 @@ # BR Code A crate to parse and emit [PIX BR Code](https://www.bcb.gov.br/content/estabilidadefinanceira/spb_docs/ManualBRCode.pdf). +* [Technical and Business specs for BR Code usage](https://www.bcb.gov.br/content/estabilidadefinanceira/forumpireunioes/Anexo%20I%20-%20QRCodes%20-%20Especifica%C3%A7%C3%A3o%20-%20vers%C3%A3o%201-1.pdf) + ## Usage ```toml [dependencies] -brcode = "1.0.1" +brcode = "1.1.0" ``` Shellscript to get files from release: @@ -483,6 +485,11 @@ time: [33.238 us 33.555 us 33.924 us] time: [24.537 us 25.391 us 26.260 us] ``` +**crc16_ccitt** in `benches/crc16`: +``` +time: [3.0738 us 3.0825 us 3.0938 us] +``` + ## Goals - [x] Parse BR Code String; - [x] Parse BR Code to `BrCode` struct; diff --git a/benches/crc16.rs b/benches/crc16.rs new file mode 100644 index 0000000..731af71 --- /dev/null +++ b/benches/crc16.rs @@ -0,0 +1,15 @@ +use brcode::crc16_ccitt; +use criterion::{criterion_group, criterion_main, Criterion}; + +fn criterion_benchmark(c: &mut Criterion) { + let message = message(); + c.bench_function("crc16", |b| b.iter(|| crc16_ccitt(&message))); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); + +fn message() -> String { + "00020104141234567890123426580014BR.GOV.BCB.PIX0136123e4567-e12b-12d1-a456-42665544000027300012BR.COM.OUTRO011001234567895204000053039865406123.455802BR5917NOME DO RECEBEDOR6008BRASILIA61087007490062190515RP12345678-201980390012BR.COM.OUTRO01190123.ABCD.3456.WXYZ6304" + .to_string() +} diff --git a/src/aux.rs b/src/aux.rs index 95cfb4e..f8afb5e 100644 --- a/src/aux.rs +++ b/src/aux.rs @@ -51,6 +51,29 @@ impl FromIterator<(usize, parse::Data)> for HashBrCode { } } +pub fn crc16_ccitt(message: &str) -> String { + let mut crc: u16 = 0xFFFF; // initial value + let polynomial: u16 = 0x1021; // 0001 0000 0010 0001 (0, 5, 12) + + // byte[] testBytes = "123456789".getBytes("ASCII"); + + let bytes = message.as_bytes(); + + for b in bytes { + for i in 0u16..8u16 { + let bit = (b >> (7-i) & 1) == 1; + let c15 = (crc >> 15 & 1) == 1; + crc <<= 1; + if c15 ^ bit {crc ^= polynomial}; + } + } + + crc &= 0xffff; + + + format!("{:X}", crc) +} + #[cfg(test)] mod test { use super::*; @@ -71,6 +94,14 @@ mod test { assert_eq!(hash.0, expected); } + #[test] + fn test_crc16_ccitt() { + let crc16 = crc16_ccitt("123456789"); + let expected = "29B1"; + + assert_eq!(crc16, expected); + } + #[test] fn creates_nested_map() { let vec = vec![ diff --git a/src/lib.rs b/src/lib.rs index b3b5c88..7d3c7e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub(crate) mod parse; pub use model::{BrCode, Info, Label, MerchantInfo, Template}; pub use parse::Data; +pub use aux::crc16_ccitt; pub fn from_str(code: &str) -> Vec<(usize, parse::Data)> { parse::parse(code, 99) diff --git a/src/model.rs b/src/model.rs index 285d23e..092ee5b 100644 --- a/src/model.rs +++ b/src/model.rs @@ -179,10 +179,11 @@ impl BrCode { m.info.iter().for_each(|i| { encode.push_str(&format!("{:02}{:02}{}", i.id, i.info.len(), i.info)); }); - }), //TODO + }), } - encode.push_str(&format!("6304{:04}", self.crc1610)); - + encode.push_str("6304"); + let crc16 = crate::aux::crc16_ccitt(&encode); + encode.push_str(&crc16); encode } } diff --git a/tests/lib.rs b/tests/lib.rs index 6590e3f..5203b12 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -16,6 +16,14 @@ fn test_to_string() { assert_eq!(actual, expected); } +#[test] +fn assert_both_ways() { + let from = brcode::from_str(&dynamic_code()); + let to = brcode::to_string(from); + + assert_eq!(to, dynamic_code()) +} + #[test] fn test_brcode_to_string() { let actual = brcode::brcode_to_string(brcode_expected()); @@ -77,6 +85,11 @@ fn json_to_brcode_ffi() { assert_eq!(actual, code); } +fn dynamic_code() -> String { + "00020101021226740014br.gov.bcb.spi210812345678220412342308123456782420001122334455667788995204000053039865406123.455802BR5913FULANO DE TAL6008BRASILIA62190515RP12345678-201980720014br.gov.bcb.spi2550bx.com.br/spi/U0VHUkVET1RPVEFMTUVOVEVBTEVBVE9SSU8=630434D1" + .to_string() +} + fn code() -> String { "00020104141234567890123426580014BR.GOV.BCB.PIX0136123e4567-e12b-12d1-a456-42665544000027300012BR.COM.OUTRO011001234567895204000053039865406123.455802BR5917NOME DO RECEBEDOR6008BRASILIA61087007490062190515RP12345678-201980390012BR.COM.OUTRO01190123.ABCD.3456.WXYZ6304AD38" .to_string()